Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ annotation @G: @Retention(RUNTIME)
boolean[] fieldC
int fieldD
int fieldE

Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,12 @@ public void wpiPrepareClassForWriting(
return;
}

// fields
for (Map.Entry<String, FieldAnnos> fieldEntry : classAnnos.fields.entrySet()) {
fieldEntry.getValue().removePrimaryTopAnnotations();
}

// methods
for (Map.Entry<String, CallableDeclarationAnnos> methodEntry :
classAnnos.callableDeclarations.entrySet()) {
String jvmSignature = methodEntry.getKey();
Expand Down Expand Up @@ -1103,7 +1109,7 @@ public void writeResultsToFile(OutputFormat outputFormat, BaseTypeChecker checke
private void writeAjavaFile(Path outputPath, CompilationUnitAnnos root) {
try (Writer writer = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8)) {

// This commented implementation uses JavaParser's lexical preserving printing, which
// This commented one-line implementation uses JavaParser's lexical preserving printing, which
// writes the file such that its formatting is close to the original source file it was
// parsed from as possible. It is commented out because the JavaParser feature is very buggy
// and crashes when adding annotations in certain locations.
Expand Down Expand Up @@ -1885,6 +1891,21 @@ public void transferAnnotations() {
}
}

/** Removes the primary annotations in the signature that are the top in their hierarchy. */
public void removePrimaryTopAnnotations() {
if (returnType != null) {
returnType.removePrimaryTopAnnotations();
}
if (receiverType != null) {
receiverType.removePrimaryTopAnnotations();
}
if (parameterTypes != null) {
for (AnnotatedTypeMirror atm : parameterTypes) {
atm.removePrimaryTopAnnotations();
}
Comment on lines +1902 to +1905
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.

}
}

@Override
public String toString() {
StringJoiner sj =
Expand Down Expand Up @@ -2047,6 +2068,13 @@ public void transferAnnotations() {
declaration.setType(newType);
}

/** Removes the top annotations from this. */
public void removePrimaryTopAnnotations() {
if (type != null) {
type.removePrimaryTopAnnotations();
}
}

@Override
public String toString() {
return "FieldAnnos [declaration=" + declaration + ", type=" + type + "]";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5606,6 +5606,10 @@ public boolean wpiShouldInferTypesForReceivers() {
*
* @param className the class that contains the method, for diagnostics only
* @param methodAnnos the method or constructor annotations to modify
* @see #wpiPrepareMethodForWriting(
* WholeProgramInferenceJavaParserStorage.CallableDeclarationAnnos,
* Collection<WholeProgramInferenceJavaParserStorage.CallableDeclarationAnnos>,
* Collection<WholeProgramInferenceJavaParserStorage.CallableDeclarationAnnos>)
*/
public void wpiPrepareMethodForWriting(String className, AMethod methodAnnos) {
// This implementation does nothing.
Expand Down Expand Up @@ -5676,6 +5680,11 @@ public void wpiPrepareMethodForWriting(
false,
false);
}

// Remove top annotations on the method signature after the above runs.
// This side effect won't affect any future call to wpiPrepareMethodForWriting, because
// methodAnnos is a deep copy of the real inference storage data structure.
methodAnnos.removePrimaryTopAnnotations();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ public boolean removePrimaryAnnotationByClass(Class<? extends Annotation> a) {
* Remove any primary annotation that is in the same qualifier hierarchy as the parameter.
*
* @param a an annotation from the same qualifier hierarchy
* @return if an annotation was removed
* @return true if an annotation was removed
*/
public boolean removePrimaryAnnotationInHierarchy(AnnotationMirror a) {
AnnotationMirror prev = this.getPrimaryAnnotationInHierarchy(a);
Expand All @@ -747,6 +747,17 @@ public boolean removePrimaryAnnotationInHierarchy(AnnotationMirror a) {
return false;
}

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

* @return true if an annotation was removed
*/
public boolean removePrimaryTopAnnotations() {
int oldSize = primaryAnnotations.size();
primaryAnnotations.removeIf(am -> atypeFactory.isTop(am));
return oldSize != primaryAnnotations.size();
}

/**
* Removes multiple primary annotations from the type.
*
Expand Down
Loading