package org.checkerframework.checker.lock; import com.sun.source.tree.BinaryTree; import com.sun.source.tree.CompoundAssignmentTree; import com.sun.source.tree.Tree.Kind; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.javacutil.TypesUtils; public class LockTreeAnnotator extends TreeAnnotator { public LockTreeAnnotator(AnnotatedTypeFactory atypeFactory) { super(atypeFactory); } @Override public Void visitBinary(BinaryTree node, AnnotatedTypeMirror type) { // For any binary operation whose LHS or RHS can be a non-boolean type, // and whose resulting type is necessarily boolean, the resulting annotation // on the boolean type must be @GuardedBy({}). // There is no need to enforce that the annotation on the result of &&, ||, etc. // is @GuardedBy({}) since for such operators, both operands are of type // @GuardedBy({}) boolean to begin with. if (isBinaryComparisonOrInstanceOfOperator(node.getKind()) || TypesUtils.isString(type.getUnderlyingType())) { // A boolean or String is always @GuardedBy({}). LockVisitor determines whether // the LHS and RHS of this operation can be legally dereferenced. type.replaceAnnotation(((LockAnnotatedTypeFactory) atypeFactory).GUARDEDBY); return null; } return super.visitBinary(node, type); } /** Indicates that the result of the operation is a boolean value. */ private static boolean isBinaryComparisonOrInstanceOfOperator(Kind opKind) { switch (opKind) { case EQUAL_TO: case NOT_EQUAL_TO: // Technically, <=, <, > and >= are irrelevant for visitBinary, since currently boxed primitives // cannot be annotated with @GuardedBy(...), but they are left here in case that rule changes. case LESS_THAN: case LESS_THAN_EQUAL: case GREATER_THAN: case GREATER_THAN_EQUAL: case INSTANCE_OF: return true; default: } return false; } @Override public Void visitCompoundAssignment(CompoundAssignmentTree node, AnnotatedTypeMirror type) { if (TypesUtils.isString(type.getUnderlyingType())) { type.replaceAnnotation(((LockAnnotatedTypeFactory) atypeFactory).GUARDEDBY); } return super.visitCompoundAssignment(node, type); } }