Skip to content

Don't output top annotations to .ajava files#6432

Open
mernst wants to merge 9 commits intotypetools:masterfrom
mernst:ainfer-no-top
Open

Don't output top annotations to .ajava files#6432
mernst wants to merge 9 commits intotypetools:masterfrom
mernst:ainfer-no-top

Conversation

@mernst
Copy link
Copy Markdown
Member

@mernst mernst commented Jan 30, 2024

Merge after #6431

@kelloggm
Copy link
Copy Markdown
Contributor

While this change looks sensible, I can't see a difference between the output of this PR and master on either ./gradlew ainferResourceLeakAjavaTest or ./gradlew ainferIndexAjavaTest, both of which seem to already not include any top annotations on master. Can you point to a test case for which you expect this PR to change the output (even if that test case's .ajava files need to be inspected by-hand to see the difference)?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

This PR extends whole-program inference (WPI) output preparation by introducing mechanisms to remove primary top-level annotations from type signatures before writing. Changes include adding a new public method removePrimaryTopAnnotations() to AnnotatedTypeMirror that removes top annotations from the primary annotation set, introducing removal propagation methods in CallableDeclarationAnnos and FieldAnnos, modifying WholeProgramInferenceJavaParserStorage to normalize field annotations during output preparation, and updating wpiPrepareMethodForWriting to clear top-level annotations from method signatures. A trailing blank line was also removed from a test resource file.

Possibly related PRs

Suggested reviewers

  • smillst
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java (1)

973-980: ⚠️ Potential issue | 🟠 Major

Move field cleanup before the early return.

Line 974 returns before Lines 977-980, so classes with only fields never run removePrimaryTopAnnotations() for fields. That leaves top qualifiers in .ajava output for those classes.

Proposed fix
   public void wpiPrepareClassForWriting(
       ClassOrInterfaceAnnos classAnnos,
       Collection<@BinaryName String> supertypes,
       Collection<@BinaryName String> subtypes) {
-    if (classAnnos.callableDeclarations.isEmpty()) {
-      return;
-    }
-
     // fields
     for (Map.Entry<String, FieldAnnos> fieldEntry : classAnnos.fields.entrySet()) {
       fieldEntry.getValue().removePrimaryTopAnnotations();
     }
 
     // methods
     for (Map.Entry<String, CallableDeclarationAnnos> methodEntry :
         classAnnos.callableDeclarations.entrySet()) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java`
around lines 973 - 980, The field cleanup loop is skipped when
classAnnos.callableDeclarations is empty because the early return occurs before
iterating classAnnos.fields; move the fields cleanup so
removePrimaryTopAnnotations() runs regardless of callableDeclarations (i.e., run
the loop over classAnnos.fields before the if
(classAnnos.callableDeclarations.isEmpty()) return) to ensure fields have top
annotations removed; update WholeProgramInferenceJavaParserStorage accordingly,
referencing classAnnos, callableDeclarations, fields, and
removePrimaryTopAnnotations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java`:
- Around line 1918-1921: parameterTypes may contain null entries and
dereferencing them in WholeProgramInferenceJavaParserStorage causes NPEs; update
the loop that iterates over parameterTypes to guard each slot before calling
AnnotatedTypeMirror.removePrimaryTopAnnotations() by skipping or handling nulls
(e.g., check that each atm != null before invoking
removePrimaryTopAnnotations()) so only non-null AnnotatedTypeMirror instances
are dereferenced.

In
`@framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeMirror.java`:
- Around line 762-763: The JavaDoc on the method in AnnotatedTypeMirror that
currently reads "Remove any annotation that is the top annotation in its
qualifier hierarchy." is too broad — change the wording to explicitly state the
method only removes the primary (top) annotation in a qualifier hierarchy and
does not remove other annotations in that hierarchy; e.g., replace with "Remove
the primary (top) annotation in its qualifier hierarchy" and add a short
clarifying sentence that only the top/primary annotation is removed (update any
`@param/`@return descriptions as needed to reflect this narrower behavior).

---

Outside diff comments:
In
`@framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java`:
- Around line 973-980: The field cleanup loop is skipped when
classAnnos.callableDeclarations is empty because the early return occurs before
iterating classAnnos.fields; move the fields cleanup so
removePrimaryTopAnnotations() runs regardless of callableDeclarations (i.e., run
the loop over classAnnos.fields before the if
(classAnnos.callableDeclarations.isEmpty()) return) to ensure fields have top
annotations removed; update WholeProgramInferenceJavaParserStorage accordingly,
referencing classAnnos, callableDeclarations, fields, and
removePrimaryTopAnnotations.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60f5c7f and 3bcc498.

📒 Files selected for processing (4)
  • annotation-file-utilities/src/test/resources/annotations/tests/classfile/all-annotations.jaif
  • framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java
  • framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java
  • framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeMirror.java
💤 Files with no reviewable changes (1)
  • annotation-file-utilities/src/test/resources/annotations/tests/classfile/all-annotations.jaif

Comment on lines +1918 to +1921
if (parameterTypes != null) {
for (AnnotatedTypeMirror atm : parameterTypes) {
atm.removePrimaryTopAnnotations();
}
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.

⚠️ Potential issue | 🔴 Critical

Guard nullable parameter slots before dereference.

parameterTypes contains nullable entries; Line 1920 can throw NullPointerException when a parameter slot has never been initialized.

Proposed fix
       if (parameterTypes != null) {
         for (AnnotatedTypeMirror atm : parameterTypes) {
-          atm.removePrimaryTopAnnotations();
+          if (atm != null) {
+            atm.removePrimaryTopAnnotations();
+          }
         }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@framework/src/main/java/org/checkerframework/common/wholeprograminference/WholeProgramInferenceJavaParserStorage.java`
around lines 1918 - 1921, parameterTypes may contain null entries and
dereferencing them in WholeProgramInferenceJavaParserStorage causes NPEs; update
the loop that iterates over parameterTypes to guard each slot before calling
AnnotatedTypeMirror.removePrimaryTopAnnotations() by skipping or handling nulls
(e.g., check that each atm != null before invoking
removePrimaryTopAnnotations()) so only non-null AnnotatedTypeMirror instances
are dereferenced.

Comment on lines +762 to +763
* Remove any annotation that is the top annotation in its qualifier hierarchy.
*
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.

⚠️ Potential issue | 🟡 Minor

JavaDoc scope is too broad; method only removes primary annotations.

Please tighten wording to match behavior and avoid API ambiguity.

Suggested doc fix
-   * Remove any annotation that is the top annotation in its qualifier hierarchy.
+   * Remove any primary annotation that is the top annotation in its qualifier hierarchy.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeMirror.java`
around lines 762 - 763, The JavaDoc on the method in AnnotatedTypeMirror that
currently reads "Remove any annotation that is the top annotation in its
qualifier hierarchy." is too broad — change the wording to explicitly state the
method only removes the primary (top) annotation in a qualifier hierarchy and
does not remove other annotations in that hierarchy; e.g., replace with "Remove
the primary (top) annotation in its qualifier hierarchy" and add a short
clarifying sentence that only the top/primary annotation is removed (update any
`@param/`@return descriptions as needed to reflect this narrower behavior).

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.

3 participants