Skip to content

Forbid annotations on supertypes - #1068

Merged
wmdietl merged 60 commits into
eisop:masterfrom
aosen-xiong:annotation-supertype
Aug 28, 2026
Merged

Forbid annotations on supertypes#1068
wmdietl merged 60 commits into
eisop:masterfrom
aosen-xiong:annotation-supertype

Conversation

@aosen-xiong

@aosen-xiong aosen-xiong commented Jan 22, 2025

Copy link
Copy Markdown
Collaborator

Fixes #1059. BaseTypeVisitor now reports annotation.on.supertype when a supported
qualifier is written on a supertype in an extends/implements clause. Only qualifiers
from the active checker are flagged, and at most one error is reported per clause.

The check lives in a new protected helper checkAnnotationOnSupertype(Tree), called
from checkExtendsOrImplements. Checkers that allow annotations on supertypes
(currently only the Tainting Checker) override this helper with an empty body.

Earlier iterations used a separate checkSupertypeAnnotations method, then a boolean
flag on checkExtendsOrImplements. Both conflated the annotation check with the
subtyping check; the dedicated helper keeps the two concerns cleanly separated.

@aosen-xiong

aosen-xiong commented Jan 28, 2025

Copy link
Copy Markdown
Collaborator Author

@wmdietl Should we also forbid annotation on supertype's type parameter? For example

public static class NullSupplier extends Supplier<@Nullable String> {}

nvm, looks like there is a reason we should allow annotation on supertype's type parameter. https://eisop.github.io/cf/manual/manual.html#annotations-are-a-contract

@aosen-xiong aosen-xiong assigned wmdietl and aosen-xiong and unassigned wmdietl Feb 14, 2025
@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Feb 23, 2025

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

Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java Outdated
Comment thread framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java Outdated
Comment thread docs/CHANGELOG.md Outdated
@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Mar 8, 2025
@aosen-xiong
aosen-xiong requested a review from wmdietl March 13, 2025 16:13
@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Mar 13, 2025

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

Adding a new checkSupertypeAnnotations in addition to the existing checkExtendsOrImplements seems very confusing. They both basically look at the same thing and the name does not make clear when to use which method.
There is no cross-reference between the methods that would help the user decide.

With the current code, checkSupertypeAnnotations forbids annotations in a location, but then checkExtendsOrImplements checks for a subtyping relation, which also is tricky to follow. Then TaintingVisitor overrides checkSupertypeAnnotations and says do nothing, which is confusing, as this now enables the check in checkExtendsOrImplements.

So try your other suggestion: have one checkExtendsOrImplements that has a boolean whether lenient or strict checks are desired. (If there is enough common code. Maybe you can just have two separate method.)
Then the current checkExtendsOrImplements will call the method with a boolean (or the strict method). And TaintingVisitor can override the method and change the behavior.

@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Jul 28, 2026
aosen-xiong and others added 12 commits August 19, 2026 17:16
…sses

framework/tests/viewpointtest/SubclassFieldInheritance.java was added by
eisop#1900, after this branch was opened.  It declares `SubA extends @A SuperClass`
and `SubB extends @b SuperClass`, which the new default annotation.on.supertype
check reports, so :framework:test failed.

Record the two errors as expected diagnostics.  Whether a receiver-dependent
type system should be exempt from the check, the way the Tainting Checker is,
is a separate question; recording the diagnostics keeps the new behavior
visible rather than hiding it behind an override in the test checker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The closed-issues entry for this change was written as a second `eisop#1015`
rather than `eisop#1059`, and rewrapping the paragraph left a trailing space
on two lines, which :docs:spotlessMiscCheck rejects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
checker/tests/nullness/AnonymousClassTypeAnnotation.java suppressed
nullness.on.supertype, a message key this branch deletes.  The suppression is
now dead: the replacement check runs from checkExtendsAndImplements, which
returns early for an anonymous class, so nothing is reported on
`new @nullable Object() {}` for the checker to suppress.  NullnessTest passes
either way.

Note that this is a loss of coverage relative to the deleted check, which ran
from processClassTree and did report on an anonymous class's supertype.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ype key"

This reverts commit 6b733422eaa6f4b2ba7d38e1acb3f0e12f2b0f14.

Restoring the suppression leaves checker/tests/nullness/
AnonymousClassTypeAnnotation.java unchanged from master, keeping this branch
to the CI fixes.  The suppression is inert here, since the replacement check
runs from checkExtendsAndImplements, which returns early for an anonymous
class; NullnessTest passes with or without it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread framework/tests/viewpointtest/SubclassFieldInheritance.java Outdated
@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Aug 28, 2026
@aosen-xiong aosen-xiong assigned wmdietl and unassigned aosen-xiong Aug 28, 2026
@wmdietl wmdietl assigned aosen-xiong and unassigned wmdietl Aug 28, 2026
aosen-xiong and others added 2 commits August 28, 2026 11:21
SubclassFieldInheritance expects annotation.on.supertype on two classes whose
subject is field inheritance, which makes it unclear why those classes annotate
their extends clause at all.  Test the check on its own instead: an annotation
on an extends clause and on an implements clause is rejected, and an annotation
on a supertype's type argument is still allowed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…itance

The extends clauses were annotated only to make the supertype agree with the
class declaration bound.  That is unrelated to what the file tests, and with
this branch it also produces an annotation.on.supertype error, so the file
asserted a diagnostic about supertype annotations while its subject is field
inheritance.

Leave the extends clauses unannotated.  The supertype is not adapted to the
class bound, so each class now reports
declaration.inconsistent.with.extends.clause instead; record that.  Every other
expected diagnostic in the file is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread framework/tests/viewpointtest/SubclassFieldInheritance.java
@wmdietl wmdietl changed the title Forbid annotations on supertype Forbid annotations on supertypes Aug 28, 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.

Okay, follow-up work in #1986

@wmdietl
wmdietl merged commit 1581c63 into eisop:master Aug 28, 2026
44 checks passed
@aosen-xiong
aosen-xiong deleted the annotation-supertype branch August 28, 2026 16:35
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.

Forbid annotations on class extends and implements clauses

3 participants