Repository navigation
SONARJAVA-6976 Clear check state after file analysis - #6144
Conversation
This comment has been minimized.
This comment has been minimized.
|
❌ Ruling needs updating. A fix PR has been created: #6145 Please review and merge it into your branch. |
|
❌ Ruling needs updating. A fix PR has been created: #6145 Please review and merge it into your branch. |
Ruling Diff SummaryDetected changes in 5 rule files: 0 issues removed, 75 issues added. S1166 (
|
✅ All code review findings resolved.
|
❌ Ruling needs updating. A fix PR has been created: #6149 Please review and merge it into your branch. |
aurelien-coet-sonarsource
left a comment
There was a problem hiding this comment.
Maybe we could also document somewhere (e.g. in .claude/commands/project-level-rules.md) that checks which use collections to store some state should override clearState to clear it between files ?
This comment is outdated. The PR should not update ruling results. |
|
|
This PR is stale because it has been open 7 days with no activity. If there is no activity in the next 7 days it will be closed automatically |
…lived processes Move cache clearing (ifStatementCache, firstNullCheckCache, safeSymbols) from the start of scanFile to a finally block, so the last scanned file's AST is not retained for the lifetime of the plugin classloader in IDE sessions (SonarLint). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove no-op pre-clear guards before reassignment in NestedIfStatementsCheck and TypeParametersShadowingCheck - Revert unnecessary mutable copy in DepthOfInheritanceTreeCheck (filteredPatterns is a property cache, not AST state) - Fix indentation in ClassImportCouplingCheck finally block - Fix MissingPackageInfoCheckTest: remove assertion on internal state that is now properly cleared in endOfAnalysis Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ghten test - RedundantTypeCastCheck: set warnings = null instead of calling .clear() on the unmodifiable list, which threw UnsupportedOperationException - ClassImportCouplingCheck: remove redundant guarded cleanup blocks that can never execute; simplify to try/finally with null assignments - CheckStateCleanupTest: fix isPropertyCache returning true on empty stream (allMatch vacuous truth) by requiring non-empty value types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…6 ruling Add a protected clearState() hook to IssuableSubscriptionVisitor, called automatically from setContext() before each file analysis. Checks that need to clear per-file state now simply override clearState() instead of duplicating the setContext/leaveFile boilerplate in every file. This eliminates ~210 lines of duplicated code across 14 checks. Also reverts the S1166 ruling file updates that were based on the bug where exceptions/exceptionIdentifiers were incorrectly cleared. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dant override - Add clearState() call in IssuableSubscriptionVisitor.leaveFile() so state is released after the last file analysis, not just before the next one - Remove redundant setContext() override in UnusedPrivateFieldCheck since the base class already calls clearState() in setContext() - Remove unused JavaFileScannerContext import in UnreachableCatchCheck (SQ QG) - Relax ArchUnit test to accept field cleared by any lifecycle method, since clearState() is called from both setContext() and leaveFile() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ontext/leaveFile Address review feedback: override clearState() in StaticFieldInitializationCheck, CookieHttpOnlyCheck, SecureCookieCheck, DateEnumsCheck, HardcodedURICheck, and WaitInWhileLoopCheck instead of duplicating cleanup logic in setContext/leaveFile. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…inal Add a "Per-File State Cleanup" section to CLAUDE.md explaining how rules should clear mutable state between files: via clearState() for IssuableSubscriptionVisitor, or in scanFile()'s finally block for BaseTreeVisitor/JavaFileScanner. Also make CatchUsesExceptionWithContextCheck's excludedCatchTrees field final to reflect it is never reassigned. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
e9d0162 to
d1d5231
Compare
When a subscription visitor fails during the visit and a state cleanup also fails, report the primary failure in fail-fast mode instead of letting the cleanup failure replace it from the finally block. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Code Review ✅ Approved 15 closed / 15 findings🟡 Medium risk · Clearing mutable state across dozens of Java checks at file boundaries could alter rule findings if cleanup timing disrupts accumulated analysis data. Clears collection-backed check state through a new ✅ 15 closed✅ Bug: S1166: exclusion list wiped after first file (false positives)
✅ Bug: S6539: imports never recomputed after first file
✅ Bug: S120: project-level accumulator cleared at start of each file
✅ Quality: CheckStateCleanupTest does not enforce what it claims
✅ Performance: IndentationCheck copies all file lines just to clear them
...and 10 more closed from earlier reviews Review coverage🧪 Functional validation No results 📋 Rules No rules evaluated Cross-repo coverage 4 repositories selected 🤖 Auto-approval Not enabled · Set up OptionsAuto-apply is off → Gitar will not commit updates to this branch. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar |
|
aurelien-coet-sonarsource
left a comment
There was a problem hiding this comment.
LGTM, thank you for the changes ! 👍




Summary
Validation
Agent workflow
Addressed review comments in pr_report_6144.md using
uv run address_reviews.py pr_report_6144.mdPR updated using
uv run update_with_claude.py --prompt "Implement the action plan described in the document [MAJOR] Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception. (component: java-frontend/src/test/java/org/sonar/java/model/VisitorsBridgeTest.java, line: 187)." -a "[MAJOR] Refactor the code of the lambda to have only one invocation possibly throwing a runtime exception. (component: java-frontend/src/test/java/org/sonar/java/model/VisitorsBridgeTest.java, line: 187)" -g "claude"PR updated using
uv run update_with_claude.py --prompt "Implement the action plan described in the document Code Review: Clears per-file check state through a newclearState()hook after file analysis, resolving earlier issues with S1166 exclusions, S6539 imports, and S120 accumulators being wiped between files. Approved with suggestions: inIssuableSubscriptionVisitorsRunner.scanFile, a cleanup failure thrown from thefinallyblock can replace the original fail-fastAnalysisException, hiding the root-cause check failure. Consider tracking whether the main body already failed, or attaching the cleanup failure withaddSuppressed`.💡 Edge Case: Cleanup failure in finally masks the original fail-fast exception
Files: java-frontend/src/main/java/org/sonar/java/model/VisitorsBridge.java:433-447
In
IssuableSubscriptionVisitorsRunner.scanFile, when fail-fast is on andsetContext/visit/leaveFilefails,interruptIfFailFast(e)at line 436 throws anAnalysisException. The newfinallyblock then runsclearStateAfterFileon every visitor. If any of those cleanups also fails,interruptIfFailFast(cleanupFailure)at line 455 throws a secondAnalysisException. Because it is thrown fromfinally, it replaces the first one, so the root-cause check failure is dropped from the propagated exception (the cleanup only shows up in the logs). This is likely to happen, sinceclearState()now runs on visitors whose state may be half-built after the failed visit. Fix: track whether the main body already failed, and only rethrow the cleanup failure when it did not, or attach the cleanup failure withaddSuppressed.Fix (Only rethrow the cleanup failure when no primary failure is already propagating):
CheckFailureException primaryFailure = null;
try {
forEach(subscriptionVisitors, s -> s.setContext(javaFileScannerContext));
visit(javaFileScannerContext.getTree());
forEach(subscriptionVisitors, s -> s.leaveFile(javaFileScannerContext));
} catch (CheckFailureException e) {
primaryFailure = e;
} finally {
CheckFailureException cleanupFailure = clearAllStates();
issuableSubscriptionVisitorsDuration.stop();
CheckFailureException toReport = primaryFailure != null ? primaryFailure : cleanupFailure;
if (toReport != null) {
interruptIfFailFast(toReport);
}
}." -a "Code Review: Clears per-file check state through a new
clearState()hook after file analysis, resolving earlier issues with S1166 exclusions, S6539 imports, and S120 accumulators being wiped between files. Approved with suggestions: inIssuableSubscriptionVisitorsRunner.scanFile, a cleanup failure thrown from thefinallyblock can replace the original fail-fastAnalysisException, hiding the root-cause check failure. Consider tracking whether the main body already failed, or attaching the cleanup failure withaddSuppressed.💡 Edge Case: Cleanup failure in finally masks the original fail-fast exception
Files: java-frontend/src/main/java/org/sonar/java/model/VisitorsBridge.java:433-447
In
IssuableSubscriptionVisitorsRunner.scanFile, when fail-fast is on andsetContext/visit/leaveFilefails,interruptIfFailFast(e)at line 436 throws anAnalysisException. The newfinallyblock then runsclearStateAfterFileon every visitor. If any of those cleanups also fails,interruptIfFailFast(cleanupFailure)at line 455 throws a secondAnalysisException. Because it is thrown fromfinally, it replaces the first one, so the root-cause check failure is dropped from the propagated exception (the cleanup only shows up in the logs). This is likely to happen, sinceclearState()now runs on visitors whose state may be half-built after the failed visit. Fix: track whether the main body already failed, and only rethrow the cleanup failure when it did not, or attach the cleanup failure withaddSuppressed.Fix (Only rethrow the cleanup failure when no primary failure is already propagating):
CheckFailureException primaryFailure = null;
try {
forEach(subscriptionVisitors, s -> s.setContext(javaFileScannerContext));
visit(javaFileScannerContext.getTree());
forEach(subscriptionVisitors, s -> s.leaveFile(javaFileScannerContext));
} catch (CheckFailureException e) {
primaryFailure = e;
} finally {
CheckFailureException cleanupFailure = clearAllStates();
issuableSubscriptionVisitorsDuration.stop();
CheckFailureException toReport = primaryFailure != null ? primaryFailure : cleanupFailure;
if (toReport != null) {
interruptIfFailFast(toReport);
}
}" -g "claude"`