package checkers.javari; import javax.annotation.processing.*; import javax.lang.model.element.*; import checkers.basetype.*; import checkers.quals.TypeQualifiers; import checkers.types.*; import checkers.types.AnnotatedTypeMirror.AnnotatedDeclaredType; import checkers.util.AnnotationUtils; import checkers.javari.quals.*; /** * An annotation processor that checks a program's use of the Javari * type annotations ({@code @ReadOnly}, {@code @Mutable}, * {@code @Assignable}, {@code @PolyRead} and {@code @QReadOnly}). * * @checker.framework.manual #javari-checker Javari Checker */ @TypeQualifiers( { ReadOnly.class, ThisMutable.class, Mutable.class, PolyRead.class, QReadOnly.class }) public class JavariChecker extends BaseTypeChecker { protected AnnotationMirror READONLY, THISMUTABLE, MUTABLE, POLYREAD, QREADONLY, ASSIGNABLE; /** * Initializes the checker: calls init method on super class, * creates a local AnnotationFactory based on the processing * environment, and uses it to create the protected * AnnotationMirrors used through this checker. * @param processingEnv the processing environment to use in the local AnnotationFactory */ @Override public synchronized void init(ProcessingEnvironment processingEnv) { AnnotationUtils annoFactory = AnnotationUtils.getInstance(processingEnv); this.READONLY = annoFactory.fromClass(ReadOnly.class); this.THISMUTABLE = annoFactory.fromClass(ThisMutable.class); this.MUTABLE = annoFactory.fromClass(Mutable.class); this.POLYREAD = annoFactory.fromClass(PolyRead.class); this.QREADONLY = annoFactory.fromClass(QReadOnly.class); this.ASSIGNABLE = annoFactory.fromClass(Assignable.class); super.init(processingEnv); } /** * Implements the {@code @QReadOnly} behavior on generic types, * creating a new {@link TypeHierarchy} class that allows a * comparison of type arguments to succeed if the left hand side * is annotated with {@code @QReadOnly} or if the regular * comparison succeeds. */ @Override protected TypeHierarchy createTypeHierarchy() { return new TypeHierarchy(getQualifierHierarchy()) { @Override protected boolean isSubtypeAsTypeArgument(AnnotatedTypeMirror rhs, AnnotatedTypeMirror lhs) { return lhs.hasAnnotation(QREADONLY) || super.isSubtypeAsTypeArgument(rhs, lhs); } }; } /** * Checks if one the parameters is primitive, or if a type is * subtype of another. Primitive types always pass to avoid issues * with boxing. */ @Override public boolean isSubtype(AnnotatedTypeMirror sub, AnnotatedTypeMirror sup) { return sub.getKind().isPrimitive() || sup.getKind().isPrimitive() || super.isSubtype(sub, sup); } /** * Always true; no type validity checking is made by the BaseTypeVisitor. * * @see BaseTypeVisitor */ @Override public boolean isValidUse(AnnotatedDeclaredType elemType, AnnotatedDeclaredType useType) { return true; } }