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 4d8c10156590..146264175bc5 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -355,9 +355,6 @@ public class AnnotatedTypeFactory implements AnnotationProvider { /** The checker to use for option handling and resource management. */ protected final BaseTypeChecker checker; - /** Map keys are canonical names of aliased annotations. */ - private final Map<@FullyQualifiedName String, Alias> aliases = new HashMap<>(); - /** * Scans all parts of the {@link AnnotatedTypeMirror} so that all of its fields are initialized. */ @@ -394,6 +391,19 @@ public void initializeAtm(AnnotatedTypeMirror type) { atmInitializer.visit(type); } + /** Map keys are canonical names of aliased annotations. */ + private final Map<@FullyQualifiedName String, Alias> aliases = new HashMap<>(); + + /** + * A map from the canonical name of a declaration annotation to the mapping of the canonical name + * of a declaration annotation with the same meaning (an alias) to the annotation mirror that + * should be used instead (an instance of the canonical declaration annotation). + */ + // A further generalization is to do something similar to `aliases`, where we allow copying + // elements from the alias to the canonical annotation. + private final Map<@FullyQualifiedName String, Map<@FullyQualifiedName String, AnnotationMirror>> + declAliases = new HashMap<>(); + /** * Information about one annotation alias. * @@ -460,14 +470,6 @@ void checkRep(String aliasName) { } } - /** - * A map from the class of an annotation to the set of classes for annotations with the same - * meaning, as well as the annotation mirror that should be used. - */ - private final Map< - Class, IPair>>> - declAliases = new HashMap<>(); - /** Unique ID counter; for debugging purposes. */ private static int uidCounter = 0; @@ -3507,18 +3509,37 @@ protected void addAliasedDeclAnnotation( Class alias, Class annotationClass, AnnotationMirror annotationToUse) { - IPair>> pair = - declAliases.get(annotationClass); - if (pair != null) { - if (!AnnotationUtils.areSame(annotationToUse, pair.first)) { - throw new BugInCF("annotationToUse should be the same: %s %s", pair.first, annotationToUse); - } - } else { - pair = IPair.of(annotationToUse, new HashSet<>()); - declAliases.put(annotationClass, pair); + addAliasedDeclAnnotation( + alias.getCanonicalName(), annotationClass.getCanonicalName(), annotationToUse); + } + + /** + * Add the annotation {@code alias} as an alias for the declaration annotation {@code annotation}, + * where the annotation mirror {@code annotationToUse} will be used instead. If multiple calls are + * made with the same {@code annotation}, then the {@code annotationToUse} must be the same. + * + *

The point of {@code annotationToUse} is that it may include elements/fields. + * + * @param alias the fully-qualified name of the alias annotation + * @param annotationName the fully-qualified name of the canonical annotation + * @param annotationToUse the annotation mirror to use + */ + protected void addAliasedDeclAnnotation( + @FullyQualifiedName String alias, + @FullyQualifiedName String annotationName, + AnnotationMirror annotationToUse) { + Map<@FullyQualifiedName String, AnnotationMirror> mapping = declAliases.get(annotationName); + if (mapping == null) { + mapping = new HashMap<>(1); + declAliases.put(annotationName, mapping); + } + AnnotationMirror prev = mapping.put(alias, annotationToUse); + // There already was a mapping. Raise an error. + if (prev != null && !AnnotationUtils.areSame(prev, annotationToUse)) { + throw new TypeSystemError( + "Multiple aliases for %s: %s cannot map to %s and %s.", + annotationName, alias, prev, annotationToUse); } - Set> aliases = pair.second; - aliases.add(alias); } /** @@ -3939,10 +3960,32 @@ public boolean shouldWarnIfStubRedundantWithBytecode() { */ private @Nullable AnnotationMirror getDeclAnnotation( Element elt, Class annoClass, boolean checkAliases) { + return getDeclAnnotation(elt, annoClass.getCanonicalName(), checkAliases); + } + + /** + * Returns the actual annotation mirror used to annotate this element, whose name equals the + * passed canonical annotation name (or is an alias for it). Returns null if none exists. May + * return the canonical annotation that annotationName is an alias for. + * + *

An option is provided not to check for aliases of annotations. For example, an annotated + * type factory may use aliasing for a pair of annotations for convenience while needing in some + * cases to determine a strict ordering between them, such as when determining whether the + * annotations on an overrider method are more specific than the annotations of an overridden + * method. + * + * @param elt the element to retrieve the annotation from + * @param annoName the canonical annotation name to retrieve + * @param checkAliases whether to return an annotation mirror for an alias of the requested + * annotation class name + * @return the annotation mirror for the requested annotation, or null if not found + */ + private AnnotationMirror getDeclAnnotation( + Element elt, @FullyQualifiedName String annoName, boolean checkAliases) { AnnotationMirrorSet declAnnos = getDeclAnnotations(elt); for (AnnotationMirror am : declAnnos) { - if (areSameByClass(am, annoClass)) { + if (AnnotationUtils.areSameByName(am, annoName)) { return am; } } @@ -3950,16 +3993,14 @@ public boolean shouldWarnIfStubRedundantWithBytecode() { return null; } // Look through aliases. - IPair>> aliases = declAliases.get(annoClass); + Map<@FullyQualifiedName String, AnnotationMirror> aliases = declAliases.get(annoName); if (aliases == null) { return null; } - for (Class alias : aliases.second) { - for (AnnotationMirror am : declAnnos) { - if (areSameByClass(am, alias)) { - // TODO: need to copy over elements/fields - return aliases.first; - } + for (AnnotationMirror am : declAnnos) { + AnnotationMirror match = aliases.get(AnnotationUtils.annotationName(am)); + if (match != null) { + return match; } }