Skip to content

Add test for @SuppressWarnings and @AnnotatedFor interaction and refine SourceChecker logic#1699

Open
aosen-xiong wants to merge 13 commits into
eisop:masterfrom
aosen-xiong:fix-annotatedfor-warning
Open

Add test for @SuppressWarnings and @AnnotatedFor interaction and refine SourceChecker logic#1699
aosen-xiong wants to merge 13 commits into
eisop:masterfrom
aosen-xiong:fix-annotatedfor-warning

Conversation

@aosen-xiong

Copy link
Copy Markdown
Collaborator

Fix @SuppressWarnings on an enclosing element being ignored when an inner element carries @AnnotatedFor.

The early return was redundant: the loop's natural termination already produces false when no matching @SuppressWarnings is found. Removing it lets the walk continue past @AnnotatedFor-annotated elements to enclosing scopes.

Copilot AI review requested due to automatic review settings May 5, 2026 02:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes warning suppression behavior in SourceChecker so an enclosing @SuppressWarnings still applies when an inner declaration is marked @AnnotatedFor. It also adds regression tests in both framework-level subtyping tests and nullness conservative-default tests.

Changes:

  • Removed the redundant early return in SourceChecker.shouldSuppressWarnings(Element, String) so suppression lookup continues through enclosing elements.
  • Added a subtyping regression test covering class-level @SuppressWarnings with a method-level @AnnotatedFor.
  • Added a nullness regression test covering the same interaction for nullness checking.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
framework/tests/conservative-defaults/annotatedfor/AnnotatedForTest.java Adds a regression case proving outer @SuppressWarnings("subtyping") overrides inner @AnnotatedFor("subtyping").
framework/src/main/java/org/checkerframework/framework/source/SourceChecker.java Removes the early exit that prevented suppression lookup from reaching enclosing scopes.
checker/tests/nulless-conservative-defaults/annotatedfornullness/AnnotatedForNullness.java Adds a nullness regression case for the same suppression/@AnnotatedFor interaction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@thisisalexandercook thisisalexandercook left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great catch! It may be worth noting that #1331 also removes this check as part of its broader refactor, but this bug is independent and makes sense as its own PR.

Comment thread framework/tests/conservative-defaults/annotatedfor/AnnotatedForTest.java Outdated
Co-authored-by: Alex Cook <43047600+thisisalexandercook@users.noreply.github.com>
@aosen-xiong

Copy link
Copy Markdown
Collaborator Author

Great catch! It may be worth noting that #1331 also removes this check as part of its broader refactor, but this bug is independent and makes sense as its own PR.

Thanks! Yes, that's the point of having this PR.

@wmdietl wmdietl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for looking into this!
Also, please go through the javadoc and manual and see where this behavior is described.

return true;
}
}
if (isAnnotatedForThisCheckerOrUpstreamChecker(elt)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The public boolean shouldSuppressWarnings(TreePath path, String errKey) overload still has this logic in it, twice.
Should that version continue to check for this condition?

I would expect that we need to find two things:

  1. what is the nearest SuppressWarnings?
  2. what is the nearest AnnotatedFor or UnannotatedFor?

Once we found an AnnotatedFor or UnannotatedFor, we can stop looking for the other as well, but we do need to continue looking for a SuppressWarnings, and the other way around.

Can you look through the other overload and write a test case that triggers that version?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The public boolean shouldSuppressWarnings(TreePath path, String errKey) overload still has this logic in it, twice.

Updated. The TreePath overload no longer returns immediately when it sees an applicable @AnnotatedFor.

I would expect that we need to find two things:

  1. what is the nearest SuppressWarnings?
  2. what is the nearest AnnotatedFor or UnannotatedFor?

The new logic does that by tracking whether an applicable @AnnotatedFor was found, while continuing to walk enclosing declarations for a matching @SuppressWarnings. If it finds a matching suppression, it returns true; if it found @AnnotatedFor but no suppression, it returns false.

Also, please go through the javadoc and manual and see where this behavior is described.

I updated the relevant manual sections to state that diagnostics in an @AnnotatedFor scope can still be suppressed by an in-scope @SuppressWarnings.

@aosen-xiong aosen-xiong requested a review from wmdietl May 14, 2026 03:19
@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong May 14, 2026

@wmdietl wmdietl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some high-level clarifications that I need to understand what this is trying to do.

user-written annotation, \emph{and} the checker issues no warnings.
The command-line argument \code{-AonlyAnnotatedFor} can be used to suppress errors and warnings outside of the scope of an \<@AnnotatedFor> annotation,
but does not change the default qualifiers for source code (See Section~\ref{aonlyannotatedfor}).
Warnings in code with a relevant \<@AnnotatedFor> annotation can still be suppressed by

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This sentence comes out of the blue and the connection to what's in the paragraph before is unclear. What is "still" referring to?

Would it make more sense to first keep the existing text and then say the new part? Is the "still" referring to passing -AonlyAnnotatedFor? Is that the important point?

Comment thread docs/manual/warnings.tex
You can suppress all errors and warnings for code outside of a corresponding
\code{@AnnotatedFor} by applying this command-line option.
Note that the \code{@AnnotatedFor} annotation must include the checker's name to
enable warnings from that checker, except for warnings suppressed by another

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are the "Note" and "except" part really connected? Maybe make the "except" part a separate sentence that highlights that explicit SuppressWarnings suppress warnings in AnnotatedFor code and in UnannotatedFor code (if the extra flag is not there).

* otherwise
*/
public boolean shouldSuppressWarnings(TreePath path, String errKey) {
if (shouldSuppress(getSuppressWarningsStringsFromOption(), errKey)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The shouldSuppressWarnings(Tree tree, String errKey) performs this check (with a helpful comment) and another check, before calling this method.
Adding this check here now performs this check twice.

Should both checks from the Tree version be moved to the TreePath version? Are there other places that call this method that should not have both checks?

* @param errKey the error key the checker is emitting
* @return true if {@code elt} has an corresponding {@code @SuppressWarnings} annotation
*/
private boolean shouldSuppressWarningsOnElement(Element elt, String errKey) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There already is a shouldSuppressWarnings(Element elt, String errKey) overload. What is the relationship between these two methods and why do we need both?

@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Jun 8, 2026
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.

4 participants