Skip to content

feat(forge-lint): [claude] check for unwrapped modifiers #10967

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

Merged

Conversation

0xClandestine
Copy link
Contributor

@0xClandestine 0xClandestine commented Jul 9, 2025

Motivation

Coauthored by Claude 4 Opus Max

Modifiers in Solidity that contain logic directly in their body can lead to code duplication when used across multiple functions. Since modifiers are inlined at compile time, any logic within them is duplicated for each function that uses the modifier increasing contract size and deployment cost. A common best practice is to extract modifier logic into internal functions that can be called from within the modifier, reducing code duplication and contract size.

Solution

This PR adds a new gas optimization lint unwrapped-modifier-logic that detects when modifiers contain logic directly in their body instead of using internal/private/public/library functions.

The lint checks for modifiers that contain any statements other than:

  • Direct calls to internal/private/public/library functions.
  • The placeholder _;

Example of code that triggers the lint:

modifier onlyOwner() {
    require(msg.sender == owner, "Not owner"); // Unwrapped logic
    _;
}

Recommended pattern:

modifier onlyOwner() {
    _checkOwner(); // Wrapped in internal function
    _;
}

function _checkOwner() internal view {
    require(msg.sender == owner, "Not owner");
}

PR Checklist

  • Added Tests - Created testdata/ModifierLogic.sol and testdata/ModifierLogic.stderr with comprehensive test cases
  • Added Documentation - Need to add lint documentation to the Foundry book under the gas optimization section
  • Breaking changes - No breaking changes, this is a new lint rule

@0xClandestine 0xClandestine changed the title feat(forge-lint): check for unwrapped modifiers feat(forge-lint): [claude] check for unwrapped modifiers Jul 9, 2025
@0xClandestine 0xClandestine marked this pull request as ready for review July 9, 2025 04:55
@grandizzy grandizzy requested a review from 0xrusowsky July 9, 2025 05:01
Copy link
Collaborator

@grandizzy grandizzy left a comment

Choose a reason for hiding this comment

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

thank you, makes sense. left some nits, pending @0xrusowsky @DaniPopes review

@0xrusowsky
Copy link
Contributor

overall the PR looks good, however i'd like to hold it back until we merge:

and then make it do a fix suggestion

@kaxhnet
Copy link

kaxhnet commented Jul 16, 2025

\

@grandizzy
Copy link
Collaborator

overall the PR looks good, however i'd like to hold it back until we merge:

* [feat(forge-lint): new `LateLintPass` + support code snippets #10846](https://github.com/foundry-rs/foundry/pull/10846)

and then make it do a fix suggestion

that's merged now so we can rebuild this PR on top of it

@0xrusowsky
Copy link
Contributor

@0xClandestine if u want to see an example of how to generate snippets, you can check:

note that in that case, rather than using the AST, i used the HIR cause i needed semantic info (i think that for you case the AST should be enough)

@0xClandestine 0xClandestine force-pushed the feat/claude-unwrapped-modifier-lint branch from 41fc4f8 to bed9ce0 Compare July 16, 2025 19:39
@0xClandestine 0xClandestine force-pushed the feat/claude-unwrapped-modifier-lint branch from bed9ce0 to d7a6829 Compare July 16, 2025 19:40
@0xClandestine 0xClandestine requested a review from grandizzy July 16, 2025 22:50
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 improve the code suggestions, and let's wait for others to voice their opinions on whether to use fn post_source_unit or not

@0xrusowsky 0xrusowsky moved this to In Progress in Foundry Jul 23, 2025
@0xClandestine
Copy link
Contributor Author

i've made the changes that i originally i made on: rusowsky/trim-rmv-span which improves the devex and will close:

i also pushed a follow-up commit to integrate the changes and add some minor simplifications

@0xClandestine please lmk if u'll take the migration to using the HIR otherwise i'll do it myself later on this week. The PR is almost there, we just need to polish these final details!

Yo sorry for the delay thought we were waiting on #11038, I'll give it a shot this evening. If I have issues feel free to get this across the finish line. Thanks for staying on top of this 🤝

@0xClandestine 0xClandestine requested a review from 0xrusowsky July 23, 2025 18:32
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.

overall looks good! please add tests for contract calls, and tomorrow i'll do some final cleanup 🙂

@0xClandestine 0xClandestine requested a review from 0xrusowsky July 24, 2025 14:10
0xrusowsky
0xrusowsky previously approved these changes Jul 24, 2025
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.

note for other reviewers:

i merged the changes that i originally i made on: https://github.com/foundry-rs/foundry/tree/rusowsky/trim-rmv-span which improves the devex and will close

i did it here cause it was easier to iterate and make sure that the indentation logic was correct (using the snippets of this new lint)

@0xrusowsky
Copy link
Contributor

@0xClandestine even if there is some extra feedback from others, i think you can already start your PR to the https://github.com/foundry-rs/book (the CI won't pass until the docs are updated).

Please update the forge-lint reference with your new lint + update the severity groups with the new one for codesize-related lints.

Co-authored-by: clandestine.eth <96172957+0xClandestine@users.noreply.github.com>
@0xClandestine
Copy link
Contributor Author

Copy link
Collaborator

@grandizzy grandizzy left a comment

Choose a reason for hiding this comment

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

thank you, overall lgtm, left couple of optional nits, pls check 🙏

@0xrusowsky
Copy link
Contributor

0xrusowsky commented Jul 25, 2025

@0xClandestine i'll take care of this round of feedback, as it is mostly targeted to the changes that i did to figure out the correct indentation 🤝

@0xrusowsky 0xrusowsky requested a review from grandizzy July 25, 2025 11:03
Copy link
Collaborator

@grandizzy grandizzy left a comment

Choose a reason for hiding this comment

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

lgtm!

@0xrusowsky 0xrusowsky moved this from In Progress to Ready For Review in Foundry Jul 25, 2025
@grandizzy grandizzy merged commit 54a6410 into foundry-rs:master Jul 25, 2025
22 checks passed
@github-project-automation github-project-automation bot moved this from Ready For Review to Done in Foundry Jul 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

feat(lint): auto remove indentation of code to snippets using ctx.emit_with_fix()
4 participants