blob: 12ced2aac13568e8e342887b3b4aa37161610c51 [file] [log] [blame]
package org.checkerframework.checker.index.substringindex;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.util.Elements;
import org.checkerframework.checker.index.IndexChecker;
import org.checkerframework.checker.index.OffsetDependentTypesHelper;
import org.checkerframework.checker.index.qual.SubstringIndexBottom;
import org.checkerframework.checker.index.qual.SubstringIndexFor;
import org.checkerframework.checker.index.qual.SubstringIndexUnknown;
import org.checkerframework.checker.index.upperbound.UBQualifier;
import org.checkerframework.checker.index.upperbound.UBQualifier.LessThanLengthOf;
import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.framework.type.ElementQualifierHierarchy;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper;
import org.checkerframework.javacutil.AnnotationBuilder;
import org.checkerframework.javacutil.AnnotationUtils;
/**
* Builds types with annotations from the Substring Index checker hierarchy, which contains
* the @{@link SubstringIndexFor} annotation.
*/
public class SubstringIndexAnnotatedTypeFactory extends BaseAnnotatedTypeFactory {
/** The top qualifier of the Substring Index hierarchy. */
public final AnnotationMirror UNKNOWN =
AnnotationBuilder.fromClass(elements, SubstringIndexUnknown.class);
/** The bottom qualifier of the Substring Index hierarchy. */
public final AnnotationMirror BOTTOM =
AnnotationBuilder.fromClass(elements, SubstringIndexBottom.class);
/**
* Create a new SubstringIndexAnnotatedTypeFactory.
*
* @param checker the associated checker
*/
public SubstringIndexAnnotatedTypeFactory(BaseTypeChecker checker) {
super(checker);
this.postInit();
}
/**
* Returns a mutable set of annotation classes that are supported by the Substring Index Checker.
*
* @return mutable set containing annotation classes from the Substring Index qualifier hierarchy
*/
@Override
protected Set<Class<? extends Annotation>> createSupportedTypeQualifiers() {
return new LinkedHashSet<>(
Arrays.asList(
SubstringIndexUnknown.class, SubstringIndexFor.class, SubstringIndexBottom.class));
}
@Override
protected QualifierHierarchy createQualifierHierarchy() {
return new SubstringIndexQualifierHierarchy(this.getSupportedTypeQualifiers(), elements);
}
/**
* Creates an {@link DependentTypesHelper} that allows use of addition and subtraction in the
* Substring Index Checker annotations.
*/
@Override
protected DependentTypesHelper createDependentTypesHelper() {
return new OffsetDependentTypesHelper(this);
}
/**
* The Substring Index qualifier hierarchy. The hierarchy consists of a top element {@link
* UNKNOWN} of type {@link SubstringIndexUnknown}, bottom element {@link BOTTOM} of type {@link
* SubstringIndexBottom}, and elements of type {@link SubstringIndexFor} that follow the subtyping
* relation of {@link UBQualifier}.
*/
private final class SubstringIndexQualifierHierarchy extends ElementQualifierHierarchy {
/**
* Creates a SubstringIndexQualifierHierarchy from the given classes.
*
* @param qualifierClasses classes of annotations that are the qualifiers
* @param elements element utils
*/
public SubstringIndexQualifierHierarchy(
Set<Class<? extends Annotation>> qualifierClasses, Elements elements) {
super(qualifierClasses, elements);
}
@Override
public AnnotationMirror greatestLowerBound(AnnotationMirror a1, AnnotationMirror a2) {
if (AnnotationUtils.areSame(a1, UNKNOWN)) {
return a2;
}
if (AnnotationUtils.areSame(a2, UNKNOWN)) {
return a1;
}
if (AnnotationUtils.areSame(a1, BOTTOM)) {
return a1;
}
if (AnnotationUtils.areSame(a2, BOTTOM)) {
return a2;
}
UBQualifier ubq1 =
UBQualifier.createUBQualifier(a1, (IndexChecker) checker.getUltimateParentChecker());
UBQualifier ubq2 =
UBQualifier.createUBQualifier(a2, (IndexChecker) checker.getUltimateParentChecker());
UBQualifier glb = ubq1.glb(ubq2);
return convertUBQualifierToAnnotation(glb);
}
@Override
public AnnotationMirror leastUpperBound(AnnotationMirror a1, AnnotationMirror a2) {
if (AnnotationUtils.areSame(a1, UNKNOWN)) {
return a1;
}
if (AnnotationUtils.areSame(a2, UNKNOWN)) {
return a2;
}
if (AnnotationUtils.areSame(a1, BOTTOM)) {
return a2;
}
if (AnnotationUtils.areSame(a2, BOTTOM)) {
return a1;
}
UBQualifier ubq1 =
UBQualifier.createUBQualifier(a1, (IndexChecker) checker.getUltimateParentChecker());
UBQualifier ubq2 =
UBQualifier.createUBQualifier(a2, (IndexChecker) checker.getUltimateParentChecker());
UBQualifier lub = ubq1.lub(ubq2);
return convertUBQualifierToAnnotation(lub);
}
@Override
public boolean isSubtype(AnnotationMirror subAnno, AnnotationMirror superAnno) {
if (areSameByClass(superAnno, SubstringIndexUnknown.class)) {
return true;
}
if (areSameByClass(subAnno, SubstringIndexBottom.class)) {
return true;
}
if (areSameByClass(subAnno, SubstringIndexUnknown.class)) {
return false;
}
if (areSameByClass(superAnno, SubstringIndexBottom.class)) {
return false;
}
UBQualifier subtype =
UBQualifier.createUBQualifier(subAnno, (IndexChecker) checker.getUltimateParentChecker());
UBQualifier supertype =
UBQualifier.createUBQualifier(
superAnno, (IndexChecker) checker.getUltimateParentChecker());
return subtype.isSubtype(supertype);
}
}
/**
* Converts an instance of {@link UBQualifier} to an annotation from the Substring Index
* hierarchy.
*
* @param qualifier the {@link UBQualifier} to be converted
* @return an annotation from the Substring Index hierarchy, representing {@code qualifier}
*/
public AnnotationMirror convertUBQualifierToAnnotation(UBQualifier qualifier) {
if (qualifier.isUnknown()) {
return UNKNOWN;
} else if (qualifier.isBottom()) {
return BOTTOM;
}
LessThanLengthOf ltlQualifier = (LessThanLengthOf) qualifier;
return ltlQualifier.convertToSubstringIndexAnnotation(processingEnv);
}
}