@Override public Void visitBinary(BinaryTree node, AnnotatedTypeMirror p) { if (!p.isAnnotated() && checker.isChecking()) { p.addAnnotation(checker.BOTTOM); } return super.visitBinary(node, p); }
@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); }
@Override public final boolean isSubtype(AnnotatedTypeMirror rhs, AnnotatedTypeMirror lhs) { if (lhs.getKind() == TypeKind.TYPEVAR && rhs.getKind() == TypeKind.TYPEVAR) { // TODO: Investigate whether there is a nicer and more proper way to // get assignments between two type variables working. if (lhs.getAnnotations().isEmpty()) { return true; } } // Otherwise Covariant would cause trouble. if (rhs.hasAnnotation(KeyForBottom.class)) { return true; } return super.isSubtype(rhs, lhs); }
@Override public boolean isAssignable(AnnotatedTypeMirror varType, Tree varTree) { if (varTree.getKind() == Tree.Kind.VARIABLE || varType.hasAnnotation(ASSIGNABLE)) return true; Element varElement = InternalUtils.symbol(varTree); if (varElement == null || !varElement.getKind().isField() || ElementUtils.isStatic(varElement)) return true; ExpressionTree expTree = (ExpressionTree) varTree; AnnotatedTypeMirror receiver = factory.getReceiver(expTree); boolean isAssignable = receiver.hasAnnotation(MUTABLE) || (receiver.hasAnnotation(ASSIGNS_FIELDS) && TreeUtils.isSelfAccess(expTree)); return isAssignable; }
@Override public Void visitLiteral(LiteralTree tree, AnnotatedTypeMirror type) { if (!type.isAnnotated()) { if (factory.getVisitorState().getAssignmentContext().getExplicitAnnotations().size() > 0) { for (AnnotationMirror m : factory.getVisitorState().getAssignmentContext().getExplicitAnnotations()) { type.addAnnotation(m); break; } } // type.atypeFactory.getVisitorState().getAssignmentContext().getExplicitAnnotations().size(); // // System.out.println("Visiting unannotated type~\n\n"); // // AnnotationBuilder builder = // new AnnotationBuilder(processingEnv, // Level.class.getCanonicalName()); // builder.setValue("value", "Public"); // //// type.addAnnotation(builder.build()); // // String regex = null; //// if (tree.getKind() == Tree.Kind.STRING_LITERAL) { //// regex = (String) tree.getValue(); //// } else if (tree.getKind() == Tree.Kind.CHAR_LITERAL) { //// regex = Character.toString((Character) tree.getValue()); //// } //// if (regex != null) { //// if (isRegex(regex)) { //// int groupCount = checker.getGroupCount(regex); //// type.addAnnotation(createRegexAnnotation(groupCount)); //// } else { //// type.addAnnotation(createPartialRegexAnnotation(regex)); //// } //// } } return super.visitLiteral(tree, type); }
@Override public AnnotatedTypeMirror getAnnotatedType(Tree tree) { AnnotatedTypeMirror type = super.getAnnotatedType(tree); if (tree instanceof ExpressionTree) tree = TreeUtils.skipParens((ExpressionTree) tree); Element elt = InternalUtils.symbol(tree); if (!checker.isChecking() /*&& !checker.isDefaultAnyType(type)*/ && type.isAnnotated() && !type.getKind().isPrimitive() && type.getKind() != TypeKind.NULL && (elt == null || !ElementUtils.isStatic(elt))) { // We don't want annotations on the following trees Kind kind = tree.getKind(); if (kind == Kind.METHOD_INVOCATION || kind == Kind.ARRAY_ACCESS || kind == Kind.MEMBER_SELECT || kind == Kind.CONDITIONAL_EXPRESSION) { type = type.getCopy(false); } } return type; }
@Override public Void visitTypeCast(TypeCastTree node, AnnotatedTypeMirror p) { if (!p.isAnnotated()) { // check if it is casting "this" if (TreeUtils.skipParens(node.getExpression()).toString().equals("this")) { annotateThis(p); } } return super.visitTypeCast(node, p); }
/** Tests whether t1 is a subtype of t2, with respect to IGJ Subtyping rules */ @Override public boolean isSubtype(AnnotatedTypeMirror sup, AnnotatedTypeMirror sub) { // TODO: Check that they are up to the same base // 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; AnnotatedTypes annoUtils = new AnnotatedTypes(env, factory); AnnotatedTypeMirror valueBaseType = annoUtils.asSuper(sub, sup); if (valueBaseType == null) // For now valueBaseType = sub; boolean isSubtype = isSubtypeOneLevel(sup, valueBaseType); boolean typeArgShouldBeSame = sup.hasAnnotation(MUTABLE); if ((sup.getKind() == TypeKind.DECLARED) && (valueBaseType.getKind() == TypeKind.DECLARED)) { AnnotatedDeclaredType supDecl = (AnnotatedDeclaredType) sup; AnnotatedDeclaredType subDecl = (AnnotatedDeclaredType) valueBaseType; // if (supDecl.getTypeArguments().size() != subDecl.getTypeArguments().size()) // System.out.println("Investigate this " + supDecl + " " + subDecl); for (int i = 0; i < supDecl.getTypeArguments().size() && i < subDecl.getTypeArguments().size(); ++i) { AnnotatedTypeMirror supArg = supDecl.getTypeArguments().get(i); AnnotatedTypeMirror subArg = subDecl.getTypeArguments().get(i); if (typeArgShouldBeSame) isSubtype &= isSameImmutability(supArg, subArg); else isSubtype &= isSubtype(supArg, subArg); } } else if ((sup.getKind() == TypeKind.ARRAY) && (valueBaseType.getKind() == TypeKind.ARRAY)) { AnnotatedArrayType supArr = (AnnotatedArrayType) sup; AnnotatedArrayType subArr = (AnnotatedArrayType) valueBaseType; if (typeArgShouldBeSame) isSubtype &= isSameImmutability(supArr.getComponentType(), subArr.getComponentType()); else isSubtype &= isSubtype(supArr.getComponentType(), subArr.getComponentType()); } return isSubtype; }
@Override public R visitTypeVariable(AnnotatedTypeVariable type, AnnotatedTypeMirror p) { // assert p instanceof AnnotatedTypeVariable : p; R r; if (visitedNodes.containsKey(type)) { return visitedNodes.get(type); } if (p instanceof AnnotatedTypeVariable) { AnnotatedTypeVariable tv = (AnnotatedTypeVariable) p; r = scan(type.getLowerBound(), tv.getLowerBound()); visitedNodes.put(type, r); r = scanAndReduce(type.getUpperBound(), tv.getUpperBound(), r); visitedNodes.put(type, r); } else { r = scan(type.getLowerBound(), p.getErased()); visitedNodes.put(type, r); r = scanAndReduce(type.getUpperBound(), p, r); visitedNodes.put(type, r); } return r; }
@Override public boolean isValidUse(AnnotatedTypeMirror elemType, AnnotatedTypeMirror use) { if (elemType.hasAnnotation(I) || use.hasAnnotation(READONLY)) return true; else return super.isValidUse(elemType, use); }
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))); }
public boolean isSameImmutability(AnnotatedTypeMirror sup, AnnotatedTypeMirror sub) { // 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; if (sup.hasAnnotation(PLACE_HOLDER) || sub.hasAnnotation(PLACE_HOLDER)) return true; else if (sup.hasAnnotation(READONLY)) return sub.hasAnnotation(READONLY); else if (sup.hasAnnotation(MUTABLE)) return sub.hasAnnotation(MUTABLE); else if (sup.hasAnnotation(IMMUTABLE)) return sub.hasAnnotation(IMMUTABLE); return false; }
private void annotateThis(AnnotatedTypeMirror type) { if (checker.isChecking()) return; type.clearAnnotations(); type.addAnnotation(checker.SELF); }