Skip to content

Share the @AnnotatedFor lookup between suppression and conservative defaults - #1331

Merged
wmdietl merged 38 commits into
eisop:masterfrom
aosen-xiong:code-refactor-annotatedfor
Aug 29, 2026
Merged

Share the @AnnotatedFor lookup between suppression and conservative defaults#1331
wmdietl merged 38 commits into
eisop:masterfrom
aosen-xiong:code-refactor-annotatedfor

Conversation

@aosen-xiong

@aosen-xiong aosen-xiong commented Jul 10, 2025

Copy link
Copy Markdown
Collaborator

Determining whether an element is in the scope of an @AnnotatedFor was implemented twice: SourceChecker.isAnnotatedForThisCheckerOrUpstreamChecker for warning suppression and QualifierDefaults.isElementAnnotatedForThisChecker for conservative defaults. Only the latter was cached.

Both now call SourceChecker.isElementAnnotatedForThisCheckerOrUpstreamChecker(Element), which BaseTypeChecker implements with a cache. The default implementation returns false, which is correct for a checker that does not type-check.

@aosen-xiong
aosen-xiong marked this pull request as ready for review August 26, 2025 04:00
@aosen-xiong
aosen-xiong requested a review from wmdietl August 26, 2025 04:35
Comment thread framework/src/main/java/org/checkerframework/framework/source/SourceChecker.java Outdated
Comment thread framework/src/main/java/org/checkerframework/framework/source/SourceChecker.java Outdated

@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!

Comment thread framework/src/main/java/org/checkerframework/framework/source/SourceChecker.java Outdated
@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Sep 1, 2025
@aosen-xiong
aosen-xiong requested a review from wmdietl September 4, 2025 02:25
@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Sep 4, 2025
@aosen-xiong
aosen-xiong force-pushed the code-refactor-annotatedfor branch from c10565f to eb741f4 Compare October 7, 2025 23:47
Copilot AI review requested due to automatic review settings December 19, 2025 06:28

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 refactors the cache and method for determining if an element is annotated for a checker, moving it from QualifierDefaults to AnnotatedTypeFactory to enable code reuse. The method isElementAnnotatedForThisChecker is renamed to isElementAnnotatedForThisCheckerOrUpstreamChecker and made abstract in SourceChecker.

  • Moved the isElementAnnotatedForThisChecker method and its cache from QualifierDefaults to AnnotatedTypeFactory
  • Made SourceChecker#isElementAnnotatedForThisCheckerOrUpstreamChecker an abstract method
  • Implemented the abstract method in all subclasses (BaseTypeChecker, AggregateChecker, and utility checkers)

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
QualifierDefaults.java Removed private isElementAnnotatedForThisChecker method and elementAnnotatedFors cache; updated calls to use the factory method
AnnotatedTypeFactory.java Added public isElementAnnotatedForThisCheckerOrUpstreamChecker method with the cache implementation
SourceChecker.java Changed method from private to protected abstract; removed implementation and imports; updated method calls
BaseTypeChecker.java Implemented abstract method by delegating to the type factory
AggregateChecker.java Implemented abstract method to return false (delegates to subcheckers)
SignaturePrinter.java Implemented abstract method to throw BugInCF (not expected to be called)
JavaCodeStatistics.java Implemented abstract method to throw BugInCF (not expected to be called)
AnnotationStatistics.java Implemented abstract method to throw BugInCF (not expected to be called)

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

Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeChecker.java Outdated
Comment thread framework/src/main/java/org/checkerframework/framework/source/SourceChecker.java Outdated
Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeChecker.java Outdated
@wmdietl

wmdietl commented Mar 22, 2026

Copy link
Copy Markdown
Member

@aosen-xiong Please go through the copilot suggestions and see what should be addressed.

@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Mar 22, 2026
aosen-xiong and others added 3 commits March 25, 2026 18:35
@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Mar 26, 2026
@wmdietl wmdietl changed the title Refactor cache to determine if an element is @AnnotatedFor Refactor cache to determine if an element is @AnnotatedFor Aug 28, 2026
Comment thread checker/jtreg/stubs/annotatedForSuppression/SuppressionTest.java Outdated
@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Aug 28, 2026
aosen-xiong and others added 2 commits August 28, 2026 14:24
A stub file for a class that is being compiled is used only with
-AmergeStubsWithSource.  AnnotatedTypeFactory.fromElement applies that rule to
type annotations, but getDeclAnnotations adds annotation-file declaration
annotations unconditionally, so unifying the @AnnotatedFor lookup on
getDeclAnnotation made a stub mark a source class as annotated without the
flag.

Read @AnnotatedFor off the element itself for an element declared in source
code.  This is a workaround for eisop#1987, which tracks the general problem in
getDeclAnnotations.

Add jtreg tests for both consequences of @AnnotatedFor, since master's two
implementations disagreed and the disagreement cancelled out: the suppression
test covers whether warnings inside the class are issued, and the
conservative-defaults test covers what a caller sees.  Both fail on master.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread docs/CHANGELOG.md Outdated
Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeChecker.java Outdated
aosen-xiong and others added 4 commits August 28, 2026 17:23
Whether an @AnnotatedFor written in a stub file applies to a class being
compiled is the subject of eisop#1987 and eisop#1988, not of this refactoring.
eisop#1988 adds its own test for it in checker/jtreg/stubs/issue1987.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@aosen-xiong aosen-xiong changed the title Refactor cache to determine if an element is @AnnotatedFor Share the @AnnotatedFor lookup between suppression and conservative defaults Aug 28, 2026
aosen-xiong added a commit to aosen-xiong/checker-framework that referenced this pull request Aug 29, 2026
Keep only the @NullMarked aliasing and its test.  The @AnnotatedFor cache
refactor that this branch also carried is eisop#1331; take master's version of
every file it touched, which is also how the SourceChecker conflict is
resolved.

In docs/CHANGELOG.md, keep master's entries and this branch's @NullMarked
bullet.
With -AmergeStubsWithSource the stub applies, so Lib carries
@AnnotatedFor("nullness") and is checked: `return null` from a method whose
return type defaults to @nonnull is an error.

The empty expected output recorded the two @AnnotatedFor lookups disagreeing.
Conservative defaults saw the stub, so Lib.get() was assumed to return
@nonnull, while warning suppression did not, so the null return went
unreported -- and Use accepted a value that is null at run time.  Sharing one
lookup removes that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread checker/jtreg/stubs/issue1987/WithStubAndMerge.out
@aosen-xiong

aosen-xiong commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator Author

Merging this PR enables us to merge #1304, which introduces @Nullmarked aliasing.

@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Aug 29, 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.

Thanks, I think this is very nice now.

Comment thread checker/jtreg/stubs/issue1987/WithStubAndMerge.out
@wmdietl
wmdietl merged commit 1c758d7 into eisop:master Aug 29, 2026
44 checks passed
aosen-xiong added a commit to aosen-xiong/checker-framework that referenced this pull request Aug 29, 2026
Conflict in QualifierDefaults: eisop#1331 removed isElementAnnotatedForThisChecker
and its elementAnnotatedFors cache from QualifierDefaults, so this branch's
changes to that method are obsolete.  Take master's side; the @UnannotatedFor
logic is ported to the shared lookup in a follow-up commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aosen-xiong added a commit to aosen-xiong/checker-framework that referenced this pull request Aug 29, 2026
…or scope

@UnannotatedFor was defined and given an AnnotatedTypeFactory helper, but its
effect was implemented in QualifierDefaults.isElementAnnotatedForThisChecker,
which eisop#1331 removed.  Implement it in the lookup that replaced it,
BaseTypeChecker.isElementAnnotatedForThisCheckerOrUpstreamChecker, so that it
governs both conservative defaults and warning suppression.

@AnnotatedFor is tested first, so @UnannotatedFor is purely subtractive: it
stops the walk to the enclosing element, and never overrides an explicit
@AnnotatedFor on the same element.  A nested @AnnotatedFor takes effect again.

Both shouldSuppressWarnings overloads accumulated the @AnnotatedFor answer over
every enclosing declaration, and the TreePath overload additionally asked about
the enclosing package.  That defeated the exclusion: an @UnannotatedFor class in
an @AnnotatedFor package was defaulted as unchecked code but still had its
warnings reported.  Ask isElementAnnotatedForThisCheckerOrUpstreamChecker once,
about the innermost declaration; it already resolves enclosing scopes, so the
per-level query was redundant work even before this change.

Only one cache is needed.  The element's cached boolean is the fully-resolved
scope answer, including @UnannotatedFor exclusions.

Also mirror doesUnannotatedForApplyToThisChecker on its @AnnotatedFor sibling,
and correct the @UnannotatedFor javadoc, which claimed an effect on bytecode
although the annotation has source retention.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aosen-xiong added a commit to aosen-xiong/checker-framework that referenced this pull request Aug 30, 2026
The branch was 310 commits behind, and master reworked the code it changes.
Carry the optimistic defaults forward onto master's design:

- eisop#1331 removed QualifierDefaults.isElementAnnotatedForThisChecker.  The new
  applyOptimisticDefaults calls
  BaseTypeChecker.isElementAnnotatedForThisCheckerOrUpstreamChecker instead,
  as applyConservativeDefaults now does, and shares its cache.
- applyDefaultsElement now applies a memoized, precedence-ordered default list
  from fusedDefaultsFor rather than looping per call.  Its boolean parameter
  becomes a three-valued DefaultsMode, with a third empty-scope slot and a
  third identity cache; invalidateFusedDefaults clears all six.
- applyOptimisticDefaults mirrors applyConservativeDefaults, including the
  fast path on the two flags and the isParsingAnnotationFile guard.  Without
  the guard it reaches the checker before the visitor is installed and throws
  a NullPointerException; without the fast path it costs a stub-file and
  bytecode test on every defaulted type.
- master's bytecode test is atypeFactory.isFromByteCode, not the three-part
  isElementFromByteCode/declarationFromElement/isFromStubFile check.

Keep the existing method names.  Renaming addUncheckedCodeDefault and
addUncheckedStandardDefaults would break downstream checkers, and was why this
branch disabled the JSpecify reference checker in CI; the optimistic variants
are added beside them instead, and that CI script is restored.

Fix the bytecode branch of applyOptimisticDefaults, which tested the source
flag.

Regenerate the four expected outputs in checker/jtreg/nullness/onlyannotatedfor:
the added @compile directive shifts every line number by one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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