use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class SignednessVisitor method isMaskedShift.
/**
* Determines if a right shift operation, {@code >>} or {@code >>>}, is masked with a masking
* operation of the form {@code shiftExpr & maskLit} or {@code shiftExpr | maskLit} such that
* the mask renders the shift signedness ({@code >>} vs {@code >>>}) irrelevent by destroying
* the bits duplicated into the shift result. For example, the following pairs of right shifts
* on {@code byte b} both produce the same results under any input, because of their masks:
*
* <p>{@code (b >> 4) & 0x0F == (b >>> 4) & 0x0F;}
*
* <p>{@code (b >> 4) | 0xF0 == (b >>> 4) | 0xF0;}
*
* @param shiftExpr a right shift expression: {@code expr1 >> expr2} or {@code expr1 >>> expr2}
* @return true iff the right shift is masked such that a signed or unsigned right shift has the
* same effect
*/
private boolean isMaskedShift(BinaryTree shiftExpr) {
// enclosing is the operation or statement that immediately contains shiftExpr
Tree enclosing;
// enclosingChild is the top node in the chain of nodes from shiftExpr to parent
Tree enclosingChild;
{
TreePath parentPath = visitorState.getPath().getParentPath();
enclosing = parentPath.getLeaf();
enclosingChild = enclosing;
// Strip away all parentheses from the shift operation
while (enclosing.getKind() == Kind.PARENTHESIZED) {
parentPath = parentPath.getParentPath();
enclosingChild = enclosing;
enclosing = parentPath.getLeaf();
}
}
if (!isMask(enclosing)) {
return false;
}
BinaryTree maskExpr = (BinaryTree) enclosing;
ExpressionTree shiftAmountExpr = shiftExpr.getRightOperand();
// Determine which child of maskExpr leads to shiftExpr. The other one is the mask.
ExpressionTree mask = maskExpr.getRightOperand() == enclosingChild ? maskExpr.getLeftOperand() : maskExpr.getRightOperand();
// Strip away the parentheses from the mask if any exist
mask = TreeUtils.skipParens(mask);
if (!isLiteral(shiftAmountExpr) || !isLiteral(mask)) {
return false;
}
LiteralTree shiftLit = (LiteralTree) shiftAmountExpr;
LiteralTree maskLit = (LiteralTree) mask;
return maskIgnoresMSB(maskExpr.getKind(), shiftLit, maskLit);
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class SignednessVisitor method visitBinary.
/**
* Enforces the following rules on binary operations involving Unsigned and Signed types:
*
* <ul>
* <li>Do not allow any Unsigned types or PolySigned types in {@literal {/, %}} operations.
* <li>Do not allow signed right shift {@literal {>>}} on an Unsigned type or a PolySigned type.
* <li>Do not allow unsigned right shift {@literal {>>>}} on a Signed type or a PolySigned type.
* <li>Allow any left shift {@literal {<<}}.
* <li>Do not allow non-equality comparisons {@literal {<, <=, >, >=}} on Unsigned types or
* PolySigned types.
* <li>Do not allow the mixing of Signed and Unsigned types.
* </ul>
*/
@Override
public Void visitBinary(BinaryTree node, Void p) {
// Used in diagnostic messages.
ExpressionTree leftOp = node.getLeftOperand();
ExpressionTree rightOp = node.getRightOperand();
Pair<AnnotatedTypeMirror, AnnotatedTypeMirror> argTypes = atypeFactory.binaryTreeArgTypes(node);
AnnotatedTypeMirror leftOpType = argTypes.first;
AnnotatedTypeMirror rightOpType = argTypes.second;
Tree.Kind kind = node.getKind();
switch(kind) {
case DIVIDE:
case REMAINDER:
if (hasUnsignedAnnotation(leftOpType)) {
checker.reportError(leftOp, "operation.unsignedlhs", kind, leftOpType, rightOpType);
} else if (hasUnsignedAnnotation(rightOpType)) {
checker.reportError(rightOp, "operation.unsignedrhs", kind, leftOpType, rightOpType);
}
break;
case RIGHT_SHIFT:
if (hasUnsignedAnnotation(leftOpType) && !atypeFactory.isMaskedShiftEitherSignedness(node, getCurrentPath()) && !atypeFactory.isCastedShiftEitherSignedness(node, getCurrentPath())) {
checker.reportError(leftOp, "shift.signed", kind, leftOpType, rightOpType);
}
break;
case UNSIGNED_RIGHT_SHIFT:
if (hasSignedAnnotation(leftOpType) && !atypeFactory.isMaskedShiftEitherSignedness(node, getCurrentPath()) && !atypeFactory.isCastedShiftEitherSignedness(node, getCurrentPath())) {
checker.reportError(leftOp, "shift.unsigned", kind, leftOpType, rightOpType);
}
break;
case LEFT_SHIFT:
break;
case GREATER_THAN:
case GREATER_THAN_EQUAL:
case LESS_THAN:
case LESS_THAN_EQUAL:
if (hasUnsignedAnnotation(leftOpType)) {
checker.reportError(leftOp, "comparison.unsignedlhs", leftOpType, rightOpType);
} else if (hasUnsignedAnnotation(rightOpType)) {
checker.reportError(rightOp, "comparison.unsignedrhs", leftOpType, rightOpType);
}
break;
case EQUAL_TO:
case NOT_EQUAL_TO:
if (leftOpType.hasAnnotation(Unsigned.class) && rightOpType.hasAnnotation(Signed.class)) {
checker.reportError(node, "comparison.mixed.unsignedlhs", leftOpType, rightOpType);
} else if (leftOpType.hasAnnotation(Signed.class) && rightOpType.hasAnnotation(Unsigned.class)) {
checker.reportError(node, "comparison.mixed.unsignedrhs", leftOpType, rightOpType);
}
break;
case PLUS:
if (TreeUtils.isStringConcatenation(node)) {
AnnotationMirror leftAnno = leftOpType.getEffectiveAnnotations().iterator().next();
AnnotationMirror rightAnno = rightOpType.getEffectiveAnnotations().iterator().next();
if (leftOpType.getKind() != TypeKind.CHAR && !TypesUtils.isDeclaredOfName(leftOpType.getUnderlyingType(), "java.lang.Character") && !atypeFactory.getQualifierHierarchy().isSubtype(leftAnno, atypeFactory.SIGNED)) {
checker.reportError(leftOp, "unsigned.concat");
} else if (rightOpType.getKind() != TypeKind.CHAR && !TypesUtils.isDeclaredOfName(rightOpType.getUnderlyingType(), "java.lang.Character") && !atypeFactory.getQualifierHierarchy().isSubtype(rightAnno, atypeFactory.SIGNED)) {
checker.reportError(rightOp, "unsigned.concat");
}
break;
}
// fall through
default:
if (leftOpType.hasAnnotation(Unsigned.class) && rightOpType.hasAnnotation(Signed.class)) {
checker.reportError(node, "operation.mixed.unsignedlhs", kind, leftOpType, rightOpType);
} else if (leftOpType.hasAnnotation(Signed.class) && rightOpType.hasAnnotation(Unsigned.class)) {
checker.reportError(node, "operation.mixed.unsignedrhs", kind, leftOpType, rightOpType);
}
break;
}
return super.visitBinary(node, p);
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class CFGTranslationPhaseOne method visitBinary.
@Override
public Node visitBinary(BinaryTree tree, Void p) {
// Note that for binary operations it is important to perform any required promotion on the left
// operand before generating any Nodes for the right operand, because labels must be inserted
// AFTER ALL preceding Nodes and BEFORE ALL following Nodes.
Node r = null;
Tree leftTree = tree.getLeftOperand();
Tree rightTree = tree.getRightOperand();
Tree.Kind kind = tree.getKind();
switch(kind) {
case DIVIDE:
case MULTIPLY:
case REMAINDER:
{
// see JLS 15.17
TypeMirror exprType = TreeUtils.typeOf(tree);
TypeMirror leftType = TreeUtils.typeOf(leftTree);
TypeMirror rightType = TreeUtils.typeOf(rightTree);
TypeMirror promotedType = binaryPromotedType(leftType, rightType);
Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
if (kind == Tree.Kind.MULTIPLY) {
r = new NumericalMultiplicationNode(tree, left, right);
} else if (kind == Tree.Kind.DIVIDE) {
if (TypesUtils.isIntegralPrimitive(exprType)) {
r = new IntegerDivisionNode(tree, left, right);
extendWithNodeWithException(r, arithmeticExceptionType);
} else {
r = new FloatingDivisionNode(tree, left, right);
}
} else {
assert kind == Tree.Kind.REMAINDER;
if (TypesUtils.isIntegralPrimitive(exprType)) {
r = new IntegerRemainderNode(tree, left, right);
extendWithNodeWithException(r, arithmeticExceptionType);
} else {
r = new FloatingRemainderNode(tree, left, right);
}
}
break;
}
case MINUS:
case PLUS:
{
// see JLS 15.18
// TypeMirror exprType = InternalUtils.typeOf(tree);
TypeMirror leftType = TreeUtils.typeOf(leftTree);
TypeMirror rightType = TreeUtils.typeOf(rightTree);
if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) {
assert (kind == Tree.Kind.PLUS);
Node left = stringConversion(scan(leftTree, p));
Node right = stringConversion(scan(rightTree, p));
r = new StringConcatenateNode(tree, left, right);
} else {
TypeMirror promotedType = binaryPromotedType(leftType, rightType);
Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
// set conversion.
if (kind == Tree.Kind.PLUS) {
r = new NumericalAdditionNode(tree, left, right);
} else {
assert kind == Tree.Kind.MINUS;
r = new NumericalSubtractionNode(tree, left, right);
}
}
break;
}
case LEFT_SHIFT:
case RIGHT_SHIFT:
case UNSIGNED_RIGHT_SHIFT:
{
// see JLS 15.19
Node left = unaryNumericPromotion(scan(leftTree, p));
Node right = unaryNumericPromotion(scan(rightTree, p));
if (kind == Tree.Kind.LEFT_SHIFT) {
r = new LeftShiftNode(tree, left, right);
} else if (kind == Tree.Kind.RIGHT_SHIFT) {
r = new SignedRightShiftNode(tree, left, right);
} else {
assert kind == Tree.Kind.UNSIGNED_RIGHT_SHIFT;
r = new UnsignedRightShiftNode(tree, left, right);
}
break;
}
case GREATER_THAN:
case GREATER_THAN_EQUAL:
case LESS_THAN:
case LESS_THAN_EQUAL:
{
// see JLS 15.20.1
TypeMirror leftType = TreeUtils.typeOf(leftTree);
if (TypesUtils.isBoxedPrimitive(leftType)) {
leftType = types.unboxedType(leftType);
}
TypeMirror rightType = TreeUtils.typeOf(rightTree);
if (TypesUtils.isBoxedPrimitive(rightType)) {
rightType = types.unboxedType(rightType);
}
TypeMirror promotedType = binaryPromotedType(leftType, rightType);
Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
Node node;
if (kind == Tree.Kind.GREATER_THAN) {
node = new GreaterThanNode(tree, left, right);
} else if (kind == Tree.Kind.GREATER_THAN_EQUAL) {
node = new GreaterThanOrEqualNode(tree, left, right);
} else if (kind == Tree.Kind.LESS_THAN) {
node = new LessThanNode(tree, left, right);
} else {
assert kind == Tree.Kind.LESS_THAN_EQUAL;
node = new LessThanOrEqualNode(tree, left, right);
}
extendWithNode(node);
return node;
}
case EQUAL_TO:
case NOT_EQUAL_TO:
{
// see JLS 15.21
TreeInfo leftInfo = getTreeInfo(leftTree);
TreeInfo rightInfo = getTreeInfo(rightTree);
Node left = scan(leftTree, p);
Node right = scan(rightTree, p);
if (leftInfo.isNumeric() && rightInfo.isNumeric() && !(leftInfo.isBoxed() && rightInfo.isBoxed())) {
// JLS 15.21.1 numerical equality
TypeMirror promotedType = binaryPromotedType(leftInfo.unboxedType(), rightInfo.unboxedType());
left = binaryNumericPromotion(left, promotedType);
right = binaryNumericPromotion(right, promotedType);
} else if (leftInfo.isBoolean() && rightInfo.isBoolean() && !(leftInfo.isBoxed() && rightInfo.isBoxed())) {
// JSL 15.21.2 boolean equality
left = unboxAsNeeded(left, leftInfo.isBoxed());
right = unboxAsNeeded(right, rightInfo.isBoxed());
}
Node node;
if (kind == Tree.Kind.EQUAL_TO) {
node = new EqualToNode(tree, left, right);
} else {
assert kind == Tree.Kind.NOT_EQUAL_TO;
node = new NotEqualNode(tree, left, right);
}
extendWithNode(node);
return node;
}
case AND:
case OR:
case XOR:
{
// see JLS 15.22
TypeMirror leftType = TreeUtils.typeOf(leftTree);
TypeMirror rightType = TreeUtils.typeOf(rightTree);
boolean isBooleanOp = TypesUtils.isBooleanType(leftType) && TypesUtils.isBooleanType(rightType);
Node left;
Node right;
if (isBooleanOp) {
left = unbox(scan(leftTree, p));
right = unbox(scan(rightTree, p));
} else if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) {
TypeMirror promotedType = binaryPromotedType(leftType, rightType);
left = binaryNumericPromotion(scan(leftTree, p), promotedType);
right = binaryNumericPromotion(scan(rightTree, p), promotedType);
} else {
left = unbox(scan(leftTree, p));
right = unbox(scan(rightTree, p));
}
Node node;
if (kind == Tree.Kind.AND) {
node = new BitwiseAndNode(tree, left, right);
} else if (kind == Tree.Kind.OR) {
node = new BitwiseOrNode(tree, left, right);
} else {
assert kind == Tree.Kind.XOR;
node = new BitwiseXorNode(tree, left, right);
}
extendWithNode(node);
return node;
}
case CONDITIONAL_AND:
case CONDITIONAL_OR:
{
// see JLS 15.23 and 15.24
// all necessary labels
Label rightStartL = new Label();
Label shortCircuitL = new Label();
// left-hand side
Node left = scan(leftTree, p);
ConditionalJump cjump;
if (kind == Tree.Kind.CONDITIONAL_AND) {
cjump = new ConditionalJump(rightStartL, shortCircuitL);
cjump.setFalseFlowRule(FlowRule.ELSE_TO_ELSE);
} else {
cjump = new ConditionalJump(shortCircuitL, rightStartL);
cjump.setTrueFlowRule(FlowRule.THEN_TO_THEN);
}
extendWithExtendedNode(cjump);
// right-hand side
addLabelForNextNode(rightStartL);
Node right = scan(rightTree, p);
// conditional expression itself
addLabelForNextNode(shortCircuitL);
Node node;
if (kind == Tree.Kind.CONDITIONAL_AND) {
node = new ConditionalAndNode(tree, left, right);
} else {
node = new ConditionalOrNode(tree, left, right);
}
extendWithNode(node);
return node;
}
default:
throw new BugInCF("unexpected binary tree: " + kind);
}
assert r != null : "unexpected binary tree";
extendWithNode(r);
return r;
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class CFGTranslationPhaseOne method createIncrementOrDecrementAssign.
/**
* Create assignment node which represent increment or decrement.
*
* @param target tree for assignment node. If it's null, corresponding assignment tree will be
* generated.
* @param expr expression node to be incremented or decremented
* @param isIncrement true when it's increment
* @return assignment node for corresponding increment or decrement
*/
private AssignmentNode createIncrementOrDecrementAssign(Tree target, Node expr, boolean isIncrement) {
ExpressionTree exprTree = (ExpressionTree) expr.getTree();
TypeMirror exprType = expr.getType();
TypeMirror oneType = types.getPrimitiveType(TypeKind.INT);
TypeMirror promotedType = binaryPromotedType(exprType, oneType);
LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
handleArtificialTree(oneTree);
Node exprRHS = binaryNumericPromotion(expr, promotedType);
Node one = new IntegerLiteralNode(oneTree);
one.setInSource(false);
extendWithNode(one);
one = binaryNumericPromotion(one, promotedType);
BinaryTree operTree = treeBuilder.buildBinary(promotedType, isIncrement ? Tree.Kind.PLUS : Tree.Kind.MINUS, exprTree, oneTree);
handleArtificialTree(operTree);
Node operNode;
if (isIncrement) {
operNode = new NumericalAdditionNode(operTree, exprRHS, one);
} else {
operNode = new NumericalSubtractionNode(operTree, exprRHS, one);
}
operNode.setInSource(false);
extendWithNode(operNode);
Node narrowed = narrowAndBox(operNode, exprType);
if (target == null) {
target = treeBuilder.buildAssignment(exprTree, (ExpressionTree) narrowed.getTree());
handleArtificialTree(target);
}
AssignmentNode assignNode = new AssignmentNode(target, expr, narrowed);
assignNode.setInSource(false);
extendWithNode(assignNode);
return assignNode;
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class JavaExpression method fromTree.
/**
* Converts a javac {@link ExpressionTree} to a CF JavaExpression. The result might contain {@link
* Unknown}.
*
* <p>We ignore operations such as widening and narrowing when computing the JavaExpression.
*
* @param tree a javac tree
* @return a JavaExpression for the given javac tree
*/
public static JavaExpression fromTree(ExpressionTree tree) {
JavaExpression result;
switch(tree.getKind()) {
case ARRAY_ACCESS:
ArrayAccessTree a = (ArrayAccessTree) tree;
JavaExpression arrayAccessExpression = fromTree(a.getExpression());
JavaExpression index = fromTree(a.getIndex());
result = new ArrayAccess(TreeUtils.typeOf(a), arrayAccessExpression, index);
break;
case BOOLEAN_LITERAL:
case CHAR_LITERAL:
case DOUBLE_LITERAL:
case FLOAT_LITERAL:
case INT_LITERAL:
case LONG_LITERAL:
case NULL_LITERAL:
case STRING_LITERAL:
LiteralTree vn = (LiteralTree) tree;
result = new ValueLiteral(TreeUtils.typeOf(tree), vn.getValue());
break;
case NEW_ARRAY:
NewArrayTree newArrayTree = (NewArrayTree) tree;
List<@Nullable JavaExpression> dimensions;
if (newArrayTree.getDimensions() == null) {
dimensions = Collections.emptyList();
} else {
dimensions = new ArrayList<>(newArrayTree.getDimensions().size());
for (ExpressionTree dimension : newArrayTree.getDimensions()) {
dimensions.add(fromTree(dimension));
}
}
List<JavaExpression> initializers;
if (newArrayTree.getInitializers() == null) {
initializers = Collections.emptyList();
} else {
initializers = new ArrayList<>(newArrayTree.getInitializers().size());
for (ExpressionTree initializer : newArrayTree.getInitializers()) {
initializers.add(fromTree(initializer));
}
}
result = new ArrayCreation(TreeUtils.typeOf(tree), dimensions, initializers);
break;
case METHOD_INVOCATION:
MethodInvocationTree mn = (MethodInvocationTree) tree;
assert TreeUtils.isUseOfElement(mn) : "@AssumeAssertion(nullness): tree kind";
ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn);
// Note that the method might be nondeterministic.
List<JavaExpression> parameters = CollectionsPlume.mapList(JavaExpression::fromTree, mn.getArguments());
JavaExpression methodReceiver;
if (ElementUtils.isStatic(invokedMethod)) {
@SuppressWarnings(// enclosingTypeElement(ExecutableElement): @NonNull
"nullness:assignment") @NonNull TypeElement methodType = ElementUtils.enclosingTypeElement(invokedMethod);
methodReceiver = new ClassName(methodType.asType());
} else {
methodReceiver = getReceiver(mn);
}
TypeMirror resultType = TreeUtils.typeOf(mn);
result = new MethodCall(resultType, invokedMethod, methodReceiver, parameters);
break;
case MEMBER_SELECT:
result = fromMemberSelect((MemberSelectTree) tree);
break;
case IDENTIFIER:
IdentifierTree identifierTree = (IdentifierTree) tree;
TypeMirror typeOfId = TreeUtils.typeOf(identifierTree);
Name identifierName = identifierTree.getName();
if (identifierName.contentEquals("this") || identifierName.contentEquals("super")) {
result = new ThisReference(typeOfId);
break;
}
assert TreeUtils.isUseOfElement(identifierTree) : "@AssumeAssertion(nullness): tree kind";
Element ele = TreeUtils.elementFromUse(identifierTree);
if (ElementUtils.isTypeElement(ele)) {
result = new ClassName(ele.asType());
break;
}
result = fromVariableElement(typeOfId, ele);
break;
case UNARY_PLUS:
return fromTree(((UnaryTree) tree).getExpression());
case BITWISE_COMPLEMENT:
case LOGICAL_COMPLEMENT:
case POSTFIX_DECREMENT:
case POSTFIX_INCREMENT:
case PREFIX_DECREMENT:
case PREFIX_INCREMENT:
case UNARY_MINUS:
JavaExpression operand = fromTree(((UnaryTree) tree).getExpression());
return new UnaryOperation(TreeUtils.typeOf(tree), tree.getKind(), operand);
case CONDITIONAL_AND:
case CONDITIONAL_OR:
case DIVIDE:
case EQUAL_TO:
case GREATER_THAN:
case GREATER_THAN_EQUAL:
case LEFT_SHIFT:
case LESS_THAN:
case LESS_THAN_EQUAL:
case MINUS:
case MULTIPLY:
case NOT_EQUAL_TO:
case OR:
case PLUS:
case REMAINDER:
case RIGHT_SHIFT:
case UNSIGNED_RIGHT_SHIFT:
case XOR:
BinaryTree binaryTree = (BinaryTree) tree;
JavaExpression left = fromTree(binaryTree.getLeftOperand());
JavaExpression right = fromTree(binaryTree.getRightOperand());
return new BinaryOperation(TreeUtils.typeOf(tree), tree.getKind(), left, right);
default:
result = null;
}
if (result == null) {
result = new Unknown(tree);
}
return result;
}
Aggregations