Skip to content

feat(lint): add UnsafeTypecast lint #11046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

TropicalDog17
Copy link
Contributor

Motivation

Closes #11029

Solution

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

warning[unsafe-typecast]: typecasts that can truncate values should be avoided
--> ROOT/testdata/UnsafeTypecast.sol:LL:CC
|
5 | uint128 b = uint128(a);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uint128 -> uint128 is safe
uintN -> uintN is always safe
intN -> intN is always safe

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a is an address type so i think it still unsafe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely ensure the compiler isn't catching some of these, cannot directly convert an address to uint128 without a compile error.

warning[unsafe-typecast]: typecasts that can truncate values should be avoided
--> ROOT/testdata/UnsafeTypecast.sol:LL:CC
|
94 | uint128 a = uint128(1000000000000000000000000000000000000000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure the compiler prevents you from downcasting a literal that's smaller than the target type size.

Comment on lines 9 to 15
warning[unsafe-typecast]: typecasts that can truncate values should be avoided
--> ROOT/testdata/UnsafeTypecast.sol:LL:CC
|
8 | uint64 c = uint64(a);
| ---------
|
= help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast
Copy link
Contributor

@0xClandestine 0xClandestine Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to emit a suggested fix as outlined in #11046

Can checkout my UnwrappedModifierLogic lint for reference #10967

@0xClandestine
Copy link
Contributor

Any updates, can update the tests for you if needed @TropicalDog17

@TropicalDog17
Copy link
Contributor Author

Hi @0xClandestine, I've updated the test, but not sure how to emit a helpful fix for the lint, can you help me on that? Thank a lot!

@0xrusowsky
Copy link
Contributor

Hi @0xClandestine, I've updated the test, but not sure how to emit a helpful fix for the lint, can you help me on that? Thank a lot!

maybe in this case a warning is enough, and no fix suggestion is required, but you could tell them to consider adding an explicit check like:

if (a > type(uint32).max) revert TypecastOverflow();

Copy link
Contributor

@0xrusowsky 0xrusowsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address the feedback

Comment on lines 91 to 97
solar_ast::LitKind::Number(num) => {
if is_negative_number_literal(num) {
Some(hir::ElementaryType::Int(solar_ast::TypeSize::ZERO))
} else {
Some(hir::ElementaryType::UInt(solar_ast::TypeSize::ZERO))
}
}
Copy link
Contributor

@0xrusowsky 0xrusowsky Jul 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the compiler performs checks when assigning literal values, i think it is safe to remove this check, which would also remove the need of the bigint dep.

Please return None and add a comment explaining the reason why


Assigning values which cannot fit into the type gives a compiler error. For example:
uint8 foo = 300;

The largest value an uint8 can hold is (2 8) - 1 = 255. So, the compiler says:
value 300 does not fit into type uint8

ref: https://solang.readthedocs.io/en/latest/language/types.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

feat(forge-lint): add UnsafeTypecast lint
3 participants