From 267166648359769c57bb28bf6e42d323b2e06cea Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Fri, 19 Jun 2026 12:50:02 -0400 Subject: [PATCH] Show extends checks with Ashowchecks --- checker/tests/command-line/Makefile | 8 +- .../command-line/issue1015/Issue1015.java | 8 ++ checker/tests/command-line/issue1015/Makefile | 9 ++ .../tests/command-line/issue1015/expected.txt | 12 +++ docs/CHANGELOG.md | 2 +- .../common/basetype/BaseTypeVisitor.java | 85 ++++++++++++++++++- 6 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 checker/tests/command-line/issue1015/Issue1015.java create mode 100644 checker/tests/command-line/issue1015/Makefile create mode 100644 checker/tests/command-line/issue1015/expected.txt diff --git a/checker/tests/command-line/Makefile b/checker/tests/command-line/Makefile index f8089d595c3d..947d3c6d6585 100644 --- a/checker/tests/command-line/Makefile +++ b/checker/tests/command-line/Makefile @@ -1,8 +1,8 @@ # All targets -.PHONY: all clean skipped issue618 +.PHONY: all clean skipped issue618 issue1015 # Tests that are currently passing -all: issue618 +all: issue618 issue1015 # Tests that are currently not passing skipped: @@ -10,5 +10,9 @@ skipped: issue618: make -C issue618 +issue1015: + make -C issue1015 + clean: make -C issue618 clean + make -C issue1015 clean diff --git a/checker/tests/command-line/issue1015/Issue1015.java b/checker/tests/command-line/issue1015/Issue1015.java new file mode 100644 index 000000000000..07a7def5a9a7 --- /dev/null +++ b/checker/tests/command-line/issue1015/Issue1015.java @@ -0,0 +1,8 @@ +import org.checkerframework.checker.tainting.qual.Tainted; +import org.checkerframework.checker.tainting.qual.Untainted; + +@Untainted class Issue1015 extends Super1015 implements Interface1015 {} + +@Untainted class Super1015 {} + +@Tainted interface Interface1015 {} diff --git a/checker/tests/command-line/issue1015/Makefile b/checker/tests/command-line/issue1015/Makefile new file mode 100644 index 000000000000..bfdd638bf8d2 --- /dev/null +++ b/checker/tests/command-line/issue1015/Makefile @@ -0,0 +1,9 @@ +.PHONY: all clean + +all: + $(JAVAC) -processor tainting -Ashowchecks Issue1015.java > out.txt 2>&1 + diff -u expected.txt out.txt + +clean: + rm -f out.txt + rm -f *.class diff --git a/checker/tests/command-line/issue1015/expected.txt b/checker/tests/command-line/issue1015/expected.txt new file mode 100644 index 000000000000..8dd36cb88087 --- /dev/null +++ b/checker/tests/command-line/issue1015/expected.txt @@ -0,0 +1,12 @@ +TaintingVisitor about to test whether the class declaration annotation is a subtype of the extends clause annotation (at Issue1015.java:4:36): extends tree = IDENTIFIER Super1015 + actual: @org.checkerframework.checker.tainting.qual.Untainted Issue1015 + expected: @org.checkerframework.checker.tainting.qual.Untainted Super1015 + success: class declaration annotation is subtype of extends clause annotation (at Issue1015.java:4:36): extends tree = IDENTIFIER Super1015 + actual: @org.checkerframework.checker.tainting.qual.Untainted Issue1015 + expected: @org.checkerframework.checker.tainting.qual.Untainted Super1015 +TaintingVisitor about to test whether the class declaration annotation is a subtype of the implements clause annotation (at Issue1015.java:4:57): implements tree = IDENTIFIER Interface1015 + actual: @org.checkerframework.checker.tainting.qual.Untainted Issue1015 + expected: @org.checkerframework.checker.tainting.qual.Tainted Interface1015 + success: class declaration annotation is subtype of implements clause annotation (at Issue1015.java:4:57): implements tree = IDENTIFIER Interface1015 + actual: @org.checkerframework.checker.tainting.qual.Untainted Issue1015 + expected: @org.checkerframework.checker.tainting.qual.Tainted Interface1015 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2e0e8f0991e3..7ce087fad015 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -231,7 +231,7 @@ median of four warm-daemon reps per side). **Closed issues:** -eisop#433, eisop#792, eisop#863, eisop#1801. +eisop#433, eisop#792, eisop#863, eisop#1015, eisop#1801. Version 3.49.5-eisop1 (April 26, 2026) diff --git a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java index ac667319c2f1..48d0abe8a5fb 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java +++ b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeVisitor.java @@ -978,7 +978,11 @@ protected void checkExtendsOrImplements( TypeMirror boundTM = boundType.getUnderlyingType(); for (AnnotationMirror classAnno : classBounds) { AnnotationMirror boundAnno = boundType.getAnnotationInHierarchy(classAnno); - if (!qualHierarchy.isSubtypeShallow(classAnno, classType, boundAnno, boundTM)) { + checkExtendsOrImplementsStartDiagnostic( + boundClause, classAnno, classType, boundAnno, boundTM, isExtends); + boolean success = + qualHierarchy.isSubtypeShallow(classAnno, classType, boundAnno, boundTM); + if (!success) { checker.reportError( boundClause, (isExtends @@ -987,6 +991,85 @@ protected void checkExtendsOrImplements( classAnno, boundAnno); } + checkExtendsOrImplementsEndDiagnostic( + success, boundClause, classAnno, classType, boundAnno, boundTM, isExtends); + } + } + + /** + * Prints a diagnostic about entering {@link #checkExtendsOrImplements}, if the showchecks + * option was set. + * + * @param boundClause an extends or implements clause + * @param classAnno the annotation on the class declaration + * @param classType the type being declared + * @param boundAnno the annotation on the extends or implements clause + * @param boundTM the type of the extends or implements clause + * @param isExtends true for an extends clause, false for an implements clause + */ + protected final void checkExtendsOrImplementsStartDiagnostic( + Tree boundClause, + AnnotationMirror classAnno, + TypeMirror classType, + AnnotationMirror boundAnno, + TypeMirror boundTM, + boolean isExtends) { + if (showchecks) { + String clause = isExtends ? "extends" : "implements"; + System.out.printf( + "%s %s (at %s): %s tree = %s %s%n actual: %s %s%n expected: %s %s%n", + this.getClass().getSimpleName(), + "about to test whether the class declaration annotation is a subtype of the " + + clause + + " clause annotation", + fileAndLineNumber(boundClause), + clause, + boundClause.getKind(), + boundClause, + classAnno, + classType, + boundAnno, + boundTM); + } + } + + /** + * Prints a diagnostic about exiting {@link #checkExtendsOrImplements}, if the showchecks option + * was set. + * + * @param success whether the check succeeded or failed + * @param boundClause an extends or implements clause + * @param classAnno the annotation on the class declaration + * @param classType the type being declared + * @param boundAnno the annotation on the extends or implements clause + * @param boundTM the type of the extends or implements clause + * @param isExtends true for an extends clause, false for an implements clause + */ + protected final void checkExtendsOrImplementsEndDiagnostic( + boolean success, + Tree boundClause, + AnnotationMirror classAnno, + TypeMirror classType, + AnnotationMirror boundAnno, + TypeMirror boundTM, + boolean isExtends) { + if (showchecks) { + String clause = isExtends ? "extends" : "implements"; + System.out.printf( + " %s (at %s): %s tree = %s %s%n actual: %s %s%n expected: %s %s%n", + (success + ? "success: class declaration annotation is subtype of " + : "FAILURE: class declaration annotation is not subtype of ") + + clause + + " clause annotation", + fileAndLineNumber(boundClause), + clause, + boundClause.getKind(), + boundClause, + classAnno, + classType, + boundAnno, + boundTM); } }