blob: 7dbbf037f8c31b24c4bd2ff56ae220f895f7f648 [file] [log] [blame]
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);
}