| 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); |
| } |
| } |