public boolean isSubtypeOneLevel(AnnotatedTypeMirror sup, AnnotatedTypeMirror sub) { // Current implementation only need to deal with one level // Err... cannot handle type variables quite yet if (sup.getKind() == TypeKind.TYPEVAR || sup.getKind() == TypeKind.WILDCARD || sub.getKind() == TypeKind.TYPEVAR || sub.getKind() == TypeKind.WILDCARD) return true; // TODO: Need to handle Generics and Arrays if (sup.hasAnnotation(READONLY) || sup.hasAnnotation(PLACE_HOLDER) || sub.hasAnnotation(PLACE_HOLDER)) return true; else if (sup.hasAnnotation(I)) { // t1 is a subtype of t2, if and only they have the same // immutability argument if (!sub.hasAnnotation(I)) return false; AnnotationUtils annoUtils = new AnnotationUtils(this.env); String t1Arg = annoUtils.parseStringValue( sub.getAnnotation(I.class.getCanonicalName()), IMMUTABILITY_KEY); String t2Arg = annoUtils.parseStringValue( sup.getAnnotation(I.class.getCanonicalName()), IMMUTABILITY_KEY); return ((t1Arg != null) && (t2Arg != null) && t1Arg.equals(t2Arg)); } return ((sup.hasAnnotation(IMMUTABLE) && sub.hasAnnotation(IMMUTABLE)) || (sup.hasAnnotation(MUTABLE) && sub.hasAnnotation(MUTABLE)) || (sup.hasAnnotation(ASSIGNS_FIELDS) && sub.hasAnnotation(ASSIGNS_FIELDS)) || (sup.hasAnnotation(ASSIGNS_FIELDS) && sub.hasAnnotation(MUTABLE))); }
protected SFlowGraphQualifierHierarchy(GraphFactory f) { super(f); reimQuals = AnnotationUtils.createAnnotationSet(); reimQuals.add(SFlowChecker.READONLY); reimQuals.add(SFlowChecker.POLYREAD); reimQuals.add(SFlowChecker.MUTABLE); }
/** * Returns the type qualifier hierarchy graph to be used by this processor. * * <p>The implementation builds the type qualifier hierarchy for the {@link * #getSupportedTypeQualifiers()} using the meta-annotations found in them. The current * implementation returns an instance of {@code GraphQualifierHierarchy}. * * <p>Subclasses may override this method to express any relationships that cannot be inferred * using meta-annotations (e.g. due to lack of meta-annotations). * * @return an annotation relation tree representing the supported qualifiers */ protected QualifierHierarchy createQualifierHierarchy() { MultiGraphQualifierHierarchy.MultiGraphFactory factory = this.createQualifierHierarchyFactory(); Elements elements = processingEnv.getElementUtils(); for (Class<? extends Annotation> typeQualifier : getSupportedTypeQualifiers()) { AnnotationMirror typeQualifierAnno = AnnotationUtils.fromClass(elements, typeQualifier); assert typeQualifierAnno != null : "Loading annotation \"" + typeQualifier + "\" failed!"; factory.addQualifier(typeQualifierAnno); // Polymorphic qualifiers can't declare their supertypes. // An error is raised if one is present. if (typeQualifier.getAnnotation(PolymorphicQualifier.class) != null) { if (typeQualifier.getAnnotation(SubtypeOf.class) != null) { // This is currently not supported. At some point we might add // polymorphic qualifiers with upper and lower bounds. errorAbort( "BaseTypeChecker: " + typeQualifier + " is polymorphic and specifies super qualifiers. " + "Remove the @checkers.quals.SubtypeOf or @checkers.quals.PolymorphicQualifier annotation from it."); } continue; } if (typeQualifier.getAnnotation(SubtypeOf.class) == null) { errorAbort( "BaseTypeChecker: " + typeQualifier + " does not specify its super qualifiers. " + "Add an @checkers.quals.SubtypeOf annotation to it."); } Class<? extends Annotation>[] superQualifiers = typeQualifier.getAnnotation(SubtypeOf.class).value(); for (Class<? extends Annotation> superQualifier : superQualifiers) { AnnotationMirror superAnno = null; superAnno = AnnotationUtils.fromClass(elements, superQualifier); factory.addSubtype(typeQualifierAnno, superAnno); } } QualifierHierarchy hierarchy = factory.build(); if (hierarchy.getTypeQualifiers().size() < 1) { errorAbort( "BaseTypeChecker: invalid qualifier hierarchy: hierarchy requires at least one annotation: " + hierarchy.getTypeQualifiers()); } return hierarchy; }
@Override public boolean isSubtype(AnnotationMirror rhs, AnnotationMirror lhs) { if (AnnotationUtils.areSameIgnoringValues(lhs, KEYFOR) && AnnotationUtils.areSameIgnoringValues(rhs, KEYFOR)) { // If they are both KeyFor annotations, they have to be equal. // TODO: or one a subset of the maps of the other? Ordering of maps? return AnnotationUtils.areSame(lhs, rhs); } // Ignore annotation values to ensure that annotation is in supertype map. if (AnnotationUtils.areSameIgnoringValues(lhs, KEYFOR)) { lhs = KEYFOR; } if (AnnotationUtils.areSameIgnoringValues(rhs, KEYFOR)) { rhs = KEYFOR; } return super.isSubtype(rhs, lhs); }
@Override public boolean isSubtype(Collection<AnnotationMirror> rhs, Collection<AnnotationMirror> lhs) { if (lhs.isEmpty() || rhs.isEmpty()) { // throw new RuntimeException("QualifierHierarchy: Empty annotations in lhs: " + // lhs + " or rhs: " + rhs); // System.err.println("WARN: QualifierHierarchy: Empty annotations in lhs: " + lhs // + " or rhs: " + rhs + " -- ignored"); return false; } // check if lhs contains Readonly and remove all ReIm annotations // I don't trust the equal method for AnnotationMirror... // FIXME: The following code is very ugly!!! boolean isLhsReadonly = false; for (Iterator<AnnotationMirror> it = lhs.iterator(); it.hasNext(); ) { AnnotationMirror anno = it.next(); if (anno.toString().equals(SFlowChecker.READONLY.toString())) { isLhsReadonly = true; } } Set<AnnotationMirror> rSet = AnnotationUtils.createAnnotationSet(); rSet.addAll(rhs); Set<AnnotationMirror> lSet = AnnotationUtils.createAnnotationSet(); lSet.addAll(lhs); rSet = InferenceUtils.differAnnotations(rSet, reimQuals); lSet = InferenceUtils.differAnnotations(lSet, reimQuals); for (AnnotationMirror lhsAnno : lSet) { for (AnnotationMirror rhsAnno : rSet) { if (isLhsReadonly || rhsAnno.toString().equals(SFlowChecker.BOTTOM.toString())) { if (isSubtype(rhsAnno, lhsAnno)) { return true; } } else { // We enforce equality if (rhsAnno.toString().equals(lhsAnno.toString())) return true; } } } return false; }
@Override public Void visitVariable(VariableTree node, AnnotatedTypeMirror p) { typeAnnotator.visit(p); VariableElement varElt = TreeUtils.elementFromDeclaration((VariableTree) node); if (!p.isAnnotated() && ElementUtils.isStatic(varElt)) { p.clearAnnotations(); Set<AnnotationMirror> set = AnnotationUtils.createAnnotationSet(); set.add(checker.ANY); set.add(checker.PEER); annotateConstants(p, set); } return super.visitVariable(node, p); }
@Override public Void visitLiteral(LiteralTree tree, AnnotatedTypeMirror type) { if (!type.isAnnotated()) { // if (type.getKind() == TypeKind.NULL) { type.clearAnnotations(); Set<AnnotationMirror> set = AnnotationUtils.createAnnotationSet(); set.add(checker.BOTTOM); annotateConstants(type, set); // } // else // type.addAnnotation(checker.READONLY); } return super.visitLiteral(tree, type); }
private void annotateMethod(ExecutableElement methodElt, AnnotatedExecutableType methodType) { if (checker.isChecking() || methodType.isAnnotated()) { return; } // First annotate the receiver annotateThis(methodType.getReceiverType()); // If it is from library if (checker.isFromLibrary(methodElt)) { Set<AnnotationMirror> set = AnnotationUtils.createAnnotationSet(); set.add(checker.PEER); annotateConstants(methodType, set); } // methodType.isAnnotated() only checks the annotations on methodType, // but not the type of its receiver, parameters or return; if (!methodType.isAnnotated()) methodType.addAnnotation(checker.BOTTOM); }
@Override protected QualifierHierarchy createQualifierHierarchy() { if (this.bottom != null) { // A special bottom qualifier was provided; go through the existing // bottom qualifiers and tie them all to this bottom qualifier. Set<AnnotationMirror> bottoms = findBottoms(supertypes, null); for (AnnotationMirror abot : bottoms) { if (!AnnotationUtils.areSame(bottom, abot)) { addSubtype(bottom, abot); } } if (!this.polyQualifiers.isEmpty()) { for (AnnotationMirror poly : polyQualifiers.values()) { addSubtype(bottom, poly); } } } return new SFlowGraphQualifierHierarchy(this); }
@Override public Void visitDeclared(AnnotatedDeclaredType type, ElementKind p) { Element elt = type.getElement(); if (!type.isAnnotated() && ( /*checker.isDefaultAnyType(type) ||*/ elt != null && ElementUtils.isStatic(elt) && (elt.getKind() == ElementKind.FIELD || elt.getKind() == ElementKind.LOCAL_VARIABLE || elt.getKind() == ElementKind.EXCEPTION_PARAMETER || elt.getKind() == ElementKind.ENUM_CONSTANT || elt.getKind() == ElementKind.PARAMETER))) { type.clearAnnotations(); Set<AnnotationMirror> set = AnnotationUtils.createAnnotationSet(); set.add(checker.ANY); if (elt != null && ElementUtils.isStatic(elt)) set.add(checker.PEER); annotateConstants(type, set); } return super.visitDeclared(type, p); }
@Override public void initChecker() { super.initChecker(); KEYFOR = AnnotationUtils.fromClass(processingEnv.getElementUtils(), KeyFor.class); }