| package org.checkerframework.framework.type; |
| |
| import java.lang.annotation.Annotation; |
| import java.util.Collection; |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.util.Elements; |
| import org.checkerframework.checker.nullness.qual.Nullable; |
| import org.checkerframework.framework.qual.AnnotatedFor; |
| import org.checkerframework.framework.util.QualifierKind; |
| import org.checkerframework.framework.util.QualifierKindHierarchy; |
| |
| /** |
| * A {@link org.checkerframework.framework.type.QualifierHierarchy} where qualifiers may be |
| * represented by annotations with elements, but most of the qualifiers do not have elements. In |
| * contrast to {@link org.checkerframework.framework.type.ElementQualifierHierarchy}, this class |
| * partially implements {@link #isSubtype(AnnotationMirror, AnnotationMirror)}, {@link |
| * #leastUpperBound(AnnotationMirror, AnnotationMirror)}, and {@link |
| * #greatestLowerBound(AnnotationMirror, AnnotationMirror)} and calls *WithElements when the result |
| * cannot be computed from the meta-annotations {@link |
| * org.checkerframework.framework.qual.SubtypeOf}. |
| * |
| * <p>Subclasses must implement the following methods when annotations have elements: |
| * |
| * <ul> |
| * <li>{@link #isSubtypeWithElements(AnnotationMirror, QualifierKind, AnnotationMirror, |
| * QualifierKind)} |
| * <li>{@link #leastUpperBoundWithElements(AnnotationMirror, QualifierKind, AnnotationMirror, |
| * QualifierKind,QualifierKind)} |
| * <li>{@link #greatestLowerBoundWithElements(AnnotationMirror, QualifierKind, AnnotationMirror, |
| * QualifierKind,QualifierKind)} |
| * </ul> |
| * |
| * <p>MostlyNoElementQualifierHierarchy uses a {@link QualifierKindHierarchy} to model the |
| * relationships between qualifiers. Subclasses can override {@link |
| * #createQualifierKindHierarchy(Collection)} to return a subclass of QualifierKindHierarchy. |
| */ |
| @AnnotatedFor("nullness") |
| public abstract class MostlyNoElementQualifierHierarchy extends ElementQualifierHierarchy { |
| |
| /** |
| * Creates a MostlyNoElementQualifierHierarchy from the given classes. |
| * |
| * @param qualifierClasses classes of annotations that are the qualifiers for this hierarchy |
| * @param elements element utils |
| */ |
| protected MostlyNoElementQualifierHierarchy( |
| Collection<Class<? extends Annotation>> qualifierClasses, Elements elements) { |
| super(qualifierClasses, elements); |
| } |
| |
| @Override |
| public final boolean isSubtype(AnnotationMirror subAnno, AnnotationMirror superAnno) { |
| QualifierKind subKind = getQualifierKind(subAnno); |
| QualifierKind superKind = getQualifierKind(superAnno); |
| if (subKind.isSubtypeOf(superKind)) { |
| if (superKind.hasElements() && subKind.hasElements()) { |
| return isSubtypeWithElements(subAnno, subKind, superAnno, superKind); |
| } else { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if {@code subAnno} is a subtype of {@code superAnno}. Both {@code subAnno} and |
| * {@code superAnno} are annotations with elements. {@code subKind} is a sub qualifier kind of |
| * {@code superKind}. |
| * |
| * @param subAnno possible subtype annotation; has elements |
| * @param subKind QualifierKind of {@code subAnno} |
| * @param superAnno possible super annotation; has elements |
| * @param superKind QualifierKind of {@code superAnno} |
| * @return true if {@code subAnno} is a subtype of {@code superAnno} |
| */ |
| protected abstract boolean isSubtypeWithElements( |
| AnnotationMirror subAnno, |
| QualifierKind subKind, |
| AnnotationMirror superAnno, |
| QualifierKind superKind); |
| |
| @Override |
| public final @Nullable AnnotationMirror leastUpperBound( |
| AnnotationMirror a1, AnnotationMirror a2) { |
| QualifierKind qual1 = getQualifierKind(a1); |
| QualifierKind qual2 = getQualifierKind(a2); |
| QualifierKind lub = qualifierKindHierarchy.leastUpperBound(qual1, qual2); |
| if (lub == null) { |
| // Qualifiers are not in the same hierarchy. |
| return null; |
| } |
| if (lub.hasElements()) { |
| return leastUpperBoundWithElements(a1, qual1, a2, qual2, lub); |
| } |
| return kindToElementlessQualifier.get(lub); |
| } |
| |
| /** |
| * Returns the least upper bound of {@code a1} and {@code a2} in cases where the lub of {@code |
| * qualifierKind1} and {@code qualifierKind2} is a qualifier kind that has elements. If the lub of |
| * {@code qualifierKind1} and {@code qualifierKind2} does not have elements, then {@link |
| * #leastUpperBound(AnnotationMirror, AnnotationMirror)} returns the correct {@code |
| * AnnotationMirror} without calling this method. |
| * |
| * @param a1 first annotation |
| * @param qualifierKind1 QualifierKind for {@code a1} |
| * @param a2 second annotation |
| * @param qualifierKind2 QualifierKind for {@code a2} |
| * @param lubKind the kind of the lub of {@code qualifierKind1} and {@code qualifierKind2} |
| * @return the least upper bound of {@code a1} and {@code a2} |
| */ |
| protected abstract AnnotationMirror leastUpperBoundWithElements( |
| AnnotationMirror a1, |
| QualifierKind qualifierKind1, |
| AnnotationMirror a2, |
| QualifierKind qualifierKind2, |
| QualifierKind lubKind); |
| |
| @Override |
| public final @Nullable AnnotationMirror greatestLowerBound( |
| AnnotationMirror a1, AnnotationMirror a2) { |
| QualifierKind qual1 = getQualifierKind(a1); |
| QualifierKind qual2 = getQualifierKind(a2); |
| QualifierKind glb = qualifierKindHierarchy.greatestLowerBound(qual1, qual2); |
| if (glb == null) { |
| // Qualifiers are not in the same hierarchy. |
| return null; |
| } |
| if (glb.hasElements()) { |
| return greatestLowerBoundWithElements(a1, qual1, a2, qual2, glb); |
| } |
| return kindToElementlessQualifier.get(glb); |
| } |
| |
| /** |
| * Returns the greatest lower bound of {@code a1} and {@code a2} in cases where the glb of {@code |
| * qualifierKind1} and {@code qualifierKind2} is a qualifier kind that has elements. If the glb of |
| * {@code qualifierKind1} and {@code qualifierKind2} does not have elements, then {@link |
| * #greatestLowerBound(AnnotationMirror, AnnotationMirror)} returns the correct {@code |
| * AnnotationMirror} without calling this method. |
| * |
| * @param a1 first annotation |
| * @param qualifierKind1 QualifierKind for {@code a1} |
| * @param a2 second annotation |
| * @param qualifierKind2 QualifierKind for {@code a2} |
| * @return the greatest lower bound between {@code a1} and {@code a2} |
| */ |
| protected abstract AnnotationMirror greatestLowerBoundWithElements( |
| AnnotationMirror a1, |
| QualifierKind qualifierKind1, |
| AnnotationMirror a2, |
| QualifierKind qualifierKind2, |
| QualifierKind glbKind); |
| } |