Skip to content

Type refinement at calls to @SideEffectsOnly methods - #7962

Closed
mernst wants to merge 31 commits into
typetools:masterfrom
mernst:side-effects-only-2-7
Closed

Type refinement at calls to @SideEffectsOnly methods#7962
mernst wants to merge 31 commits into
typetools:masterfrom
mernst:side-effects-only-2-7

Conversation

@mernst

@mernst mernst commented Aug 11, 2026

Copy link
Copy Markdown
Member

This pull request makes the annotations trusted; a subsequent PR will verify the annotations.

mernst added 15 commits August 9, 2026 11:41
containsAsReceiver() tests whether one expression is reached through another
as a receiver.  superToThis() rewrites every use of `super` as `this`.
Declare @SideEffectsOnly in checker-qual and register it as an inherited
annotation, so that it can be released and the annotated JDK can use it.  No
checker consumes it yet.

The Lock Checker deliberately ignores it: the annotation constrains which
expressions a method modifies, but promises nothing about locks.
A call to a method annotated @SideEffectsOnly no longer discards every
refinement, only those the annotation permits it to invalidate.  The
annotation is trusted here, not verified.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e3d1a746-0786-4c40-9ffc-8ed917c7654d

📥 Commits

Reviewing files that changed from the base of the PR and between cb1e4c3 and b2f5209.

📒 Files selected for processing (1)
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java

📝 Walkthrough

Walkthrough

This change adds @SideEffectsOnly expression resolution, viewpoint adaptation, inheritance, and selective refinement invalidation. It updates analysis and store handling for fields, arrays, method-call results, and receiver state. New tests cover tainting, optional presence, nullness, locking, inheritance, overrides, parse errors, and pure-call refinements. Documentation and diagnostic messages describe the annotation semantics.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/manual/called-methods-checker.tex`:
- Around line 222-234: The Called Methods Checker documentation must distinguish
`@SideEffectsOnly` from side-effect-free and pure annotations: explain that it
permits side effects and preserves a refinement only when its complete,
viewpoint-adapted list cannot affect the tracked expression, such as the
sock.close() fact; update docs/manual/called-methods-checker.tex lines 222-234
accordingly. Also update docs/manual/troubleshooting.tex line 350 to state that
the list must not affect currentOutgoing, including through an enclosing
expression.

In
`@framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java`:
- Around line 191-199: Update getSideEffectsOnlyExpressions to derive the method
from methodInvocationNode.getTarget().getMethod() before checking or populating
sideEffectsOnlyExpressionsCache, eliminating the ambiguous method parameter from
the computation path while preserving the existing cache behavior.

In
`@framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java`:
- Around line 355-370: Update mayChangeValue to use the existing alias
predicates for ArrayAccess and FieldAccess expressions, rather than relying only
on containsSyntacticEqualJavaExpression. Reuse containsModifiableAliasOf and
canAlias consistently with removeConflicting(FieldAccess, V) and
removeConflicting(ArrayAccess, V), while preserving the existing MethodCall
receiver and argument checks.
- Around line 264-272: Update thisIsSideEffected in CFAbstractStore so its
stream match treats both ThisReference and SuperReference as side-effecting
references. Keep the existing null/empty-expression behavior and
unrefinableReceiverJe exclusions unchanged.

In
`@framework/src/main/java/org/checkerframework/framework/flow/CFAbstractTransfer.java`:
- Around line 1083-1084: Replace the TODO by updating constructor handling in
visitObjectCreation to invoke store.updateForMethodCall, as method-call handling
does, so constructor side effects—including `@SideEffectsOnly` invalidation and
mutations from unannotated constructors—are reflected in type refinement at new
expressions while preserving the existing processPostconditions behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8486f66e-700b-498d-ba7c-48fa8a504dc3

📥 Commits

Reviewing files that changed from the base of the PR and between 69fbadd and dbf808a.

📒 Files selected for processing (27)
  • checker/src/main/java/org/checkerframework/checker/lock/LockAnnotatedTypeFactory.java
  • checker/src/test/java/org/checkerframework/checker/test/junit/OptionalSideEffectsTest.java
  • checker/src/test/java/org/checkerframework/checker/test/junit/SideEffectsOnlyTest.java
  • checker/tests/lock/SideEffectsOnlyLock.java
  • checker/tests/nullness/SetIteratorTest.java
  • checker/tests/nullness/SideEffectsOnlySuper.java
  • checker/tests/optional-side-effects/OptionalSideEffectsLambda.java
  • checker/tests/optional-side-effects/OptionalSideEffectsPrecondition.java
  • checker/tests/sideeffectsonly/PureMethodCallRefinement.java
  • checker/tests/sideeffectsonly/SideEffectsMultiple.java
  • checker/tests/sideeffectsonly/SideEffectsOnlyField.java
  • checker/tests/sideeffectsonly/SideEffectsOnlyTest1.java
  • checker/tests/sideeffectsonly/SideEffectsOnlyTest2.java
  • checker/tests/sideeffectsonly/SideEffectsTest1.java
  • checker/tests/sideeffectsonly/StaticIteratorSE.java
  • checker/tests/sideeffectsonly/UnrepresentableArgument.java
  • docs/CHANGELOG.md
  • docs/manual/advanced-features.tex
  • docs/manual/called-methods-checker.tex
  • docs/manual/introduction.tex
  • docs/manual/nullness-checker.tex
  • docs/manual/purity-checker.tex
  • docs/manual/troubleshooting.tex
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractTransfer.java
  • framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java
💤 Files with no reviewable changes (1)
  • checker/tests/nullness/SetIteratorTest.java

Comment thread docs/manual/called-methods-checker.tex

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java (1)

359-385: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Invalidate field and array entries that contain method-call subexpressions.

mayChangeValue follows receiver and argument dependencies only when expr is itself a MethodCall. A stored field such as c.getSelf().f or array element such as c.getArray()[0] can also depend on a listed expression. With @SideEffectsOnly("#1.f"), the nested method-call entry can be removed while the composite field or array entry retains its refinement.

Recurse through FieldAccess.getReceiver(), ArrayAccess.getArray(), and ArrayAccess.getIndex(). Add regression tests for these cases.

Proposed fix
   private static boolean mayChangeValue(JavaExpression expr, JavaExpression seOnlyExpr) {
     if (expr.containsSyntacticEqualJavaExpression(seOnlyExpr)) {
       return true;
     }
+    if (expr instanceof FieldAccess fieldAccess
+        && mayReach(seOnlyExpr, fieldAccess.getReceiver())) {
+      return true;
+    }
+    if (expr instanceof ArrayAccess arrayAccess
+        && (mayReach(seOnlyExpr, arrayAccess.getArray())
+            || mayReach(seOnlyExpr, arrayAccess.getIndex()))) {
+      return true;
+    }
     if (expr instanceof MethodCall methodCall) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java`
around lines 359 - 385, Update mayChangeValue to recurse through composite
expressions as well as MethodCall: for FieldAccess inspect its receiver, and for
ArrayAccess inspect both its array and index, using mayReach or the same
dependency checks. Ensure entries such as c.getSelf().f and c.getArray()[0] are
invalidated when their nested method-call subexpressions may change, and add
regression tests covering both cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java`:
- Around line 359-385: Update mayChangeValue to recurse through composite
expressions as well as MethodCall: for FieldAccess inspect its receiver, and for
ArrayAccess inspect both its array and index, using mayReach or the same
dependency checks. Ensure entries such as c.getSelf().f and c.getArray()[0] are
invalidated when their nested method-call subexpressions may change, and add
regression tests covering both cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 892b2d1b-3237-4657-8153-17e90583b83b

📥 Commits

Reviewing files that changed from the base of the PR and between dbf808a and b8cffff.

📒 Files selected for processing (2)
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java`:
- Around line 4158-4212: Complete the SideEffectsOnly override enforcement by
invoking checkSideEffectsOnly() at the override-validation point before
returning the result, so the parseSideEffectsOnly and sideEffectsOnlyToString
helpers are reachable and the expected purity.sideeffectsonly.overriding
diagnostics are emitted.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9ce15800-35d3-4d12-b96a-5fbabc0af1b5

📥 Commits

Reviewing files that changed from the base of the PR and between b8cffff and 138c9c7.

📒 Files selected for processing (8)
  • checker/tests/sideeffectsonly/PureMethodCallRefinement.java
  • checker/tests/sideeffectsonly/SideEffectsOnlyInherit.java
  • checker/tests/sideeffectsonly/SideEffectsOnlyOverride.java
  • checker/tests/sideeffectsonly/SideEffectsOnlyParseError.java
  • framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java
  • framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java

Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java`:
- Line 4173: Replace both `@SuppressWarnings` entries using the "UnusedMethod"
identifier with "PMD.UnusedPrivateMethod", including the suppression shown near
BaseTypeVisitor and the other matching suppression. Do not alter unrelated
suppressions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f7d2244b-976d-46c6-a99b-f409df840b01

📥 Commits

Reviewing files that changed from the base of the PR and between 138c9c7 and 73fbbd5.

📒 Files selected for processing (1)
  • framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java

Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/manual/introduction.tex (1)

621-629: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove SideEffectsOnly from the -AcheckPurityAnnotations description.

The option checks purity annotations through PurityChecker. SideEffectsOnly has no PurityKind, and its verifier remains deferred. Documenting it as checked can cause users to rely on an unchecked contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/manual/introduction.tex` around lines 621 - 629, Update the
\-AcheckPurityAnnotations item in the introduction documentation to remove the
\refqualclass{dataflow/qual}{SideEffectsOnly} annotation from the list of
annotations whose bodies are checked. Keep the descriptions of SideEffectFree,
Deterministic, and Pure unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/manual/introduction.tex`:
- Around line 621-629: Update the \-AcheckPurityAnnotations item in the
introduction documentation to remove the
\refqualclass{dataflow/qual}{SideEffectsOnly} annotation from the list of
annotations whose bodies are checked. Keep the descriptions of SideEffectFree,
Deterministic, and Pure unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a0692db6-4044-4ac1-8730-2b95387ece1f

📥 Commits

Reviewing files that changed from the base of the PR and between 73fbbd5 and a484a0c.

📒 Files selected for processing (8)
  • checker/tests/sideeffectsonly/SideEffectsOnlyOverride.java
  • docs/manual/advanced-features.tex
  • docs/manual/called-methods-checker.tex
  • docs/manual/introduction.tex
  • docs/manual/nullness-checker.tex
  • docs/manual/purity-checker.tex
  • docs/manual/troubleshooting.tex
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractTransfer.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java`:
- Around line 815-820: Update the SideEffectsOnly annotation setup in postInit()
to pass the annotation element name "value" to sideEffectsOnlyBuilder.setValue
instead of "an arbitrary value". Keep the existing arbitrary String[] value and
addInheritedAnnotation flow unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bdbdef21-8c92-49f8-aba8-1a4b1dd054cd

📥 Commits

Reviewing files that changed from the base of the PR and between a484a0c and 327cf56.

📒 Files selected for processing (5)
  • dataflow/src/main/java/org/checkerframework/dataflow/expression/JavaExpression.java
  • framework/src/main/java/org/checkerframework/common/basetype/messages.properties
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractStore.java
  • framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java

@mernstcheckerframework

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔇 Additional comments (10)
docs/manual/introduction.tex (1)

622-630: LGTM!

Also applies to: 1583-1590

checker/tests/sideeffectsonly/SideEffectsOnlyInheritScope.java (2)

38-38: The PMD UnusedLocalVariable reports are false positives. The assignments to y are the assertions that exercise the refinement, so the variables must stay.

Also applies to: 45-45


9-47: LGTM!

framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java (2)

52-52: LGTM!

Also applies to: 267-268, 729-730, 367-382, 832-835


4190-4246: LGTM!

Also applies to: 4248-4283

framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java (5)

98-135: LGTM!

Also applies to: 181-184


186-214: LGTM!


271-295: 🩺 Stability & Availability

⚠️ Unverified finding
Sandbox verification was unavailable.

Confirm that getTreePath() is non-null for every MethodInvocationNode that reaches these reports.

Lines 277 and 288 dereference methodInvocationNode.getTreePath(). The comment at lines 274-275 states that methodInvocationNode.getTree() may be null for a call that corresponds to no AST tree, such as the desugared Iterator.next() of an enhanced for loop. addSideEffectsOnlyErrorReported at line 314 also dereferences the tree path. If a node without a tree path can reach this code, the parse-error path and the warning path throw a NullPointerException instead of reporting a diagnostic.

Confirm that Node.getTreePath() is non-null for artificial nodes, or guard the two report sites.


216-270: LGTM!

Also applies to: 296-301


309-320: 📐 Maintainability & Code Quality

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify that the reference comparison at line 315 passes the Interning Checker.

Line 315 compares two CompilationUnitTree references with !=. The Checker Framework builds itself with the Interning Checker, and comparable deliberate identity comparisons in this codebase carry @SuppressWarnings("interning:not.interned"). If the Interning Checker runs over framework/src/main/java, this comparison needs a suppression or an @InternedDistinct-style declaration.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cb91cea3-52d1-4b0e-bfa3-995001ce3f8e

📥 Commits

Reviewing files that changed from the base of the PR and between 6ef1a12 and cb1e4c3.

📒 Files selected for processing (4)
  • checker/tests/sideeffectsonly/SideEffectsOnlyInheritScope.java
  • docs/manual/introduction.tex
  • framework/src/main/java/org/checkerframework/framework/flow/CFAbstractAnalysis.java
  • framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java

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.

2 participants