Skip to content

fix: candidateContractName is pure, not view - #102

Merged
thedavidmeister merged 1 commit into
mainfrom
78-candidate-contract-name-pure
Aug 16, 2026
Merged

fix: candidateContractName is pure, not view#102
thedavidmeister merged 1 commit into
mainfrom
78-candidate-contract-name-pure

Conversation

@thedavidmeister

Copy link
Copy Markdown
Contributor

Closes #78

The diff

-    function candidateContractName(DeployCandidate memory candidate) internal view returns (string memory) {
+    function candidateContractName(DeployCandidate memory candidate) internal pure returns (string memory) {

One keyword in test/src/lib/GeneratedSnapshotShape.t.sol, exactly the fix the issue proposed.

Why it is correct

The body calls only vm.split, declared external pure at dependencies/forge-std-1.16.1/src/Vm.sol:1301, against a memory argument, and vm is a constant on Test. Nothing is read from state, which is why solc can prove the restriction and emits warning 2018.

pure is accepted everywhere view was, so the sole caller — testEveryCandidateHasASnapshot at line 164 of the same file, itself view — needs no change. Those two lines are the only occurrences of the symbol in the tree.

It also puts the helper back in line with its siblings in the same file, which already track what they actually do: holdsName and artifactPath are pure, while snapshotContractNames/nodeTypes/constantDeclarations are view because they genuinely call vm.readDir/vm.readFile. candidateContractName was the odd one out, not a deliberate pattern.

QA

  • Discriminating tests: none added — n/a, and deliberately. State mutability on an internal function is a compile-time restriction with no runtime representation: there is no STATICCALL, no enforcement, nothing a test can observe. Proven rather than asserted — building both spellings and comparing the artifact for GeneratedSnapshotShapeTest gives bytecode: IDENTICAL (len 39636) and deployedBytecode: IDENTICAL (len 39522). A forge test that failed on base and passed here cannot exist, so writing one would mean asserting on source text, which this file deliberately does not do (it reads the AST precisely so formatting cannot affect it).
  • Mutations applied: test/src/lib/GeneratedSnapshotShape.t.sol:126 pure -> view (i.e. back to base). Killed by the compiler, not by a test. nix develop -c forge build --force on the mutant prints Compiler run successful with warnings: / Warning (2018): Function state mutability can be restricted to pure --> test/src/lib/GeneratedSnapshotShape.t.sol:126:5; on this branch it prints Compiler run successful! with no solc warning anywhere in the tree. The mutant SURVIVES the test suite — forge test --match-contract GeneratedSnapshotShapeTest is 5 passed / 0 failed under both spellings, with gas identical to the unit (32114, 137663, 249440, 137661, 31717). That survival is the correct result, not a coverage gap: it is the same fact as the identical bytecode above. Behavioural coverage of the function is testEveryCandidateHasASnapshot, which is unaffected because the behaviour is unchanged.
  • Oracle: solc 0.8.25's own mutability analysis, which is independent of this repo — it derived the restriction and named the line before any change was made. Backed by Vm.sol:1301 declaring split as external pure, i.e. the reason the analysis is right rather than a restatement of its output.
  • Category check: the issue asks for exactly one thing — the solc warning 2018 at GeneratedSnapshotShape.t.sol:126, with view -> pure as the proposed fix and "no caller changes" as the stated ramification. Covered: warning gone, caller verified unchanged, no other occurrence of the symbol. The issue's own verification block additionally observed that a forge-lint warning[unsafe-typecast] at src/lib/LibRainDeploy.sol:304 survives this fix, so the build is not warning-free afterwards. I confirmed it still does. That is a different finding about a different file and is deliberately NOT bundled here; this PR closes the solc-warning finding as filed.

Other verification

  • Full nix develop -c forge test: 168 passed, 47 failed. Every one of the 47 is vm.createSelectFork: environment variable <CHAIN>_RPC_URL not found — the fork tests CLAUDE.md documents as needing a gitignored .env. Environmental, untouched by this diff; CI has the secrets.
  • nix develop -c forge fmt --check passes; pre-commit hooks pass.

solc emitted warning 2018 for this helper: its body calls only
`vm.split`, declared `external pure` on `Vm`, against a `memory`
argument, and `vm` is a `constant` on `Test` — so nothing is read from
state and the compiler can prove it.

`pure` is accepted everywhere `view` was, so the sole caller
(testEveryCandidateHasASnapshot, itself `view`) is unchanged. This also
puts the helper back in line with its siblings in the same file, which
already follow the compiler: `holdsName` and `artifactPath` are `pure`,
while `snapshotContractNames`/`nodeTypes`/`constantDeclarations` are
`view` because they genuinely call `vm.readDir`/`vm.readFile`.

Closes #78

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Aug 15, 2026
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 23 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 18f7d103-1cb4-417f-8501-ef5b36168e93

📥 Commits

Reviewing files that changed from the base of the PR and between 86f8d96 and e9500ee.

📒 Files selected for processing (1)
  • test/src/lib/GeneratedSnapshotShape.t.sol

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thedavidmeister

Copy link
Copy Markdown
Contributor Author

Reviewed 9c0b1e1: ready — Closes #78. view to pure on a helper whose only call is vm.split, which forge-std declares pure on VmSafe — an external call to a pure function is permitted from a pure context, and rainix / static and rainix / test both passing is the proof it compiles under this repo's own solc.

CI green, 0 unresolved threads — vacuous, CodeRabbit reports Review rate limited.

@thedavidmeister
thedavidmeister merged commit 156ff1d into main Aug 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

solc warning 2018: candidateContractName declared view when it can be pure

1 participant