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