From 8a36dd564559dcf9091e99798add0086687e112b Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Thu, 7 Nov 2024 15:56:17 -0800 Subject: [PATCH 1/3] Add `type` as part of target location --- .../framework/qual/TypeUseLocation.java | 6 ++++++ .../framework/util/defaults/QualifierDefaults.java | 5 +++++ .../tests/viewpointtest/DefaultQualifierTest.java | 12 ++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 framework/tests/viewpointtest/DefaultQualifierTest.java diff --git a/checker-qual/src/main/java/org/checkerframework/framework/qual/TypeUseLocation.java b/checker-qual/src/main/java/org/checkerframework/framework/qual/TypeUseLocation.java index 22809919f57..c01716408a2 100644 --- a/checker-qual/src/main/java/org/checkerframework/framework/qual/TypeUseLocation.java +++ b/checker-qual/src/main/java/org/checkerframework/framework/qual/TypeUseLocation.java @@ -18,6 +18,12 @@ */ public enum TypeUseLocation { + /** + * Apply default annotations to unannotated top-level types of class, interfaces, enums and + * record * + */ + TYPE, + /** Apply default annotations to unannotated top-level types of fields. */ FIELD, diff --git a/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java b/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java index a7b7c149fe8..d739e0ed3f1 100644 --- a/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java +++ b/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java @@ -1010,6 +1010,11 @@ public Void scan(@FindDistinct AnnotatedTypeMirror t, AnnotationMirror qual) { // Some defaults only apply to the top level type. boolean isTopLevelType = t == outer.type; switch (outer.location) { + case TYPE: + if (outer.scope != null && outer.scope.getKind().isClass()) { + outer.addAnnotation(t, qual); + } + break; case FIELD: if (outer.scope != null && outer.scope.getKind() == ElementKind.FIELD diff --git a/framework/tests/viewpointtest/DefaultQualifierTest.java b/framework/tests/viewpointtest/DefaultQualifierTest.java new file mode 100644 index 00000000000..f2073d94472 --- /dev/null +++ b/framework/tests/viewpointtest/DefaultQualifierTest.java @@ -0,0 +1,12 @@ +import org.checkerframework.framework.qual.DefaultQualifier; +import org.checkerframework.framework.qual.TypeUseLocation; + +import viewpointtest.quals.*; + +@DefaultQualifier( + value = A.class, + locations = {TypeUseLocation.TYPE}) +public class DefaultQualifierTest { + // :: error: (type.invalid.annotations.on.use) + @B DefaultQualifierTest() {} +} From 6bfedba0a6b9c07ca53569d7f8d2eabc2c293d18 Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Tue, 12 Nov 2024 16:24:03 -0800 Subject: [PATCH 2/3] Try update the cache and see whether it breaks the code --- .../framework/type/AnnotatedTypeFactory.java | 2 +- .../framework/util/defaults/QualifierDefaults.java | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index 530b178c177..10c053e2515 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -526,7 +526,7 @@ void checkRep(String aliasName) { * Mapping from an Element to its annotated type; before defaults are applied, just what the * programmer wrote. */ - private final Map elementCache; + public final Map elementCache; /** Mapping from an Element to the source Tree of the declaration. */ private final Map elementToTreeCache; diff --git a/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java b/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java index d739e0ed3f1..5e0a5a889cc 100644 --- a/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java +++ b/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java @@ -1011,8 +1011,18 @@ public Void scan(@FindDistinct AnnotatedTypeMirror t, AnnotationMirror qual) { boolean isTopLevelType = t == outer.type; switch (outer.location) { case TYPE: - if (outer.scope != null && outer.scope.getKind().isClass()) { - outer.addAnnotation(t, qual); + if (outer.scope != null && outer.scope.getKind().isClass() && isTopLevelType) { + AnnotationMirror annotation = + outer.qualHierarchy.findAnnotationInHierarchy( + atypeFactory.elementCache.get(outer.scope).getAnnotations(), + qual); + if (annotation == null + || outer.qualHierarchy.isSubtypeQualifiersOnly(qual, annotation)) { + outer.addAnnotation(t, qual); + atypeFactory.elementCache.put(outer.scope, t); + } else { + // should report error; + } } break; case FIELD: From 46665734a64bc58af5440d401507f127a2088ec4 Mon Sep 17 00:00:00 2001 From: Aosen Xiong Date: Tue, 12 Nov 2024 16:39:56 -0800 Subject: [PATCH 3/3] Update the test case and getter method --- .../framework/type/AnnotatedTypeFactory.java | 7 ++++++- .../framework/util/defaults/QualifierDefaults.java | 7 +++++-- framework/tests/viewpointtest/DefaultQualifierTest.java | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index 10c053e2515..b0dd326981b 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -526,7 +526,7 @@ void checkRep(String aliasName) { * Mapping from an Element to its annotated type; before defaults are applied, just what the * programmer wrote. */ - public final Map elementCache; + private final Map elementCache; /** Mapping from an Element to the source Tree of the declaration. */ private final Map elementToTreeCache; @@ -752,6 +752,11 @@ public AnnotatedTypeFactory(BaseTypeChecker checker) { mergeStubsWithSource = checker.hasOption("mergeStubsWithSource"); } + /** Get the element cache. */ + public Map getElementCache() { + return elementCache; + } + /** * Parse a string in the format {@code * FQN.canonical.Qualifier:FQN.alias1.Qual1,FQN.alias2.Qual2} to a pair of {@code diff --git a/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java b/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java index 5e0a5a889cc..5cfaf8efbeb 100644 --- a/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java +++ b/framework/src/main/java/org/checkerframework/framework/util/defaults/QualifierDefaults.java @@ -1014,12 +1014,15 @@ public Void scan(@FindDistinct AnnotatedTypeMirror t, AnnotationMirror qual) { if (outer.scope != null && outer.scope.getKind().isClass() && isTopLevelType) { AnnotationMirror annotation = outer.qualHierarchy.findAnnotationInHierarchy( - atypeFactory.elementCache.get(outer.scope).getAnnotations(), + atypeFactory + .getElementCache() + .get(outer.scope) + .getAnnotations(), qual); if (annotation == null || outer.qualHierarchy.isSubtypeQualifiersOnly(qual, annotation)) { outer.addAnnotation(t, qual); - atypeFactory.elementCache.put(outer.scope, t); + atypeFactory.getElementCache().put(outer.scope, t); } else { // should report error; } diff --git a/framework/tests/viewpointtest/DefaultQualifierTest.java b/framework/tests/viewpointtest/DefaultQualifierTest.java index f2073d94472..f6b7e3d229e 100644 --- a/framework/tests/viewpointtest/DefaultQualifierTest.java +++ b/framework/tests/viewpointtest/DefaultQualifierTest.java @@ -7,6 +7,7 @@ value = A.class, locations = {TypeUseLocation.TYPE}) public class DefaultQualifierTest { - // :: error: (type.invalid.annotations.on.use) + // :: error: (type.invalid.annotations.on.use) :: error: (super.invocation.invalid) :: warning: + // (inconsistent.constructor.type) @B DefaultQualifierTest() {} }