use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class SignednessAnnotatedTypeFactory method isCastedShiftEitherSignedness.
/**
* Determines if a right shift operation, {@code >>} or {@code >>>}, is type casted such that the
* cast renders the shift signedness ({@code >>} vs {@code >>>}) irrelevent by discarding the bits
* duplicated into the shift result. For example, the following pair of right shifts on {@code
* short s} both produce the same results under any input, because of type casting:
*
* <p>{@code (byte)(s >> 8) == (byte)(b >>> 8);}
*
* @param shiftExpr a right shift expression: {@code expr1 >> expr2} or {@code expr1 >>> expr2}
* @param path the path to {@code shiftExpr}
* @return true iff the right shift is type casted such that a signed or unsigned right shift has
* the same effect
*/
/*package-private*/
boolean isCastedShiftEitherSignedness(BinaryTree shiftExpr, TreePath path) {
// enclosing immediately contains shiftExpr or a parenthesized version of shiftExpr
Tree enclosing = TreePathUtil.enclosingNonParen(path).first;
PrimitiveTypeTree castPrimitiveType = primitiveTypeCast(enclosing);
if (castPrimitiveType == null) {
return false;
}
TypeKind castTypeKind = castPrimitiveType.getPrimitiveTypeKind();
// Determine the type of the shift result
TypeKind shiftTypeKind = TreeUtils.typeOf(shiftExpr).getKind();
// Determine shift literal
ExpressionTree shiftAmountExpr = shiftExpr.getRightOperand();
if (!isLiteral(shiftAmountExpr)) {
return false;
}
LiteralTree shiftLit = (LiteralTree) shiftAmountExpr;
boolean result = castIgnoresMSB(shiftTypeKind, castTypeKind, shiftLit);
return result;
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class SignednessAnnotatedTypeFactory method isMaskedShiftEitherSignedness.
/**
* 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}
* @param path the path to {@code shiftExpr}
* @return true iff the right shift is masked such that a signed or unsigned right shift has the
* same effect
*/
/*package-private*/
boolean isMaskedShiftEitherSignedness(BinaryTree shiftExpr, TreePath path) {
Pair<Tree, Tree> enclosingPair = TreePathUtil.enclosingNonParen(path);
// enclosing immediately contains shiftExpr or a parenthesized version of shiftExpr
Tree enclosing = enclosingPair.first;
// enclosingChild is a child of enclosing: shiftExpr or a parenthesized version of it.
// comparing AST nodes
@SuppressWarnings("interning:assignment") @InternedDistinct Tree enclosingChild = enclosingPair.second;
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.withoutParens(mask);
if (!isLiteral(shiftAmountExpr) || !isLiteral(mask)) {
return false;
}
LiteralTree shiftLit = (LiteralTree) shiftAmountExpr;
LiteralTree maskLit = (LiteralTree) mask;
return maskIgnoresMSB(maskExpr.getKind(), shiftLit, maskLit, TreeUtils.typeOf(shiftExpr).getKind());
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class InterningVisitor method suppressEarlyEquals.
/**
* Pattern matches to prevent false positives of the forms:
*
* <pre>{@code
* (a == b) || a.equals(b)
* (a == b) || (a != null ? a.equals(b) : false)
* (a == b) || (a != null && a.equals(b))
* }</pre>
*
* Returns true iff the given node fits this pattern.
*
* @return true iff the node fits a pattern such as (a == b || a.equals(b))
*/
private boolean suppressEarlyEquals(final BinaryTree node) {
// Only handle == binary trees
if (node.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
// should strip parens
final ExpressionTree left = TreeUtils.withoutParens(node.getLeftOperand());
final ExpressionTree right = TreeUtils.withoutParens(node.getRightOperand());
// looking for ((a == b || a.equals(b))
Heuristics.Matcher matcherEqOrEquals = new Heuristics.Matcher() {
/**
* Returns true if e is either "e1 != null" or "e2 != null".
*/
private boolean isNeqNull(ExpressionTree e, ExpressionTree e1, ExpressionTree e2) {
e = TreeUtils.withoutParens(e);
if (e.getKind() != Tree.Kind.NOT_EQUAL_TO) {
return false;
}
ExpressionTree neqLeft = ((BinaryTree) e).getLeftOperand();
ExpressionTree neqRight = ((BinaryTree) e).getRightOperand();
return (((TreeUtils.sameTree(neqLeft, e1) || TreeUtils.sameTree(neqLeft, e2)) && neqRight.getKind() == Tree.Kind.NULL_LITERAL) || // also check for "null != e1" and "null != e2"
((TreeUtils.sameTree(neqRight, e1) || TreeUtils.sameTree(neqRight, e2)) && neqLeft.getKind() == Tree.Kind.NULL_LITERAL));
}
@Override
public Boolean visitBinary(BinaryTree tree, Void p) {
ExpressionTree leftTree = tree.getLeftOperand();
ExpressionTree rightTree = tree.getRightOperand();
if (tree.getKind() == Tree.Kind.CONDITIONAL_OR) {
if (TreeUtils.sameTree(leftTree, node)) {
// check right, which should be a.equals(b) or b.equals(a) or similar
return visit(rightTree, p);
} else {
return false;
}
}
if (tree.getKind() == Tree.Kind.CONDITIONAL_AND) {
// looking for: (a != null && a.equals(b)))
if (isNeqNull(leftTree, left, right)) {
return visit(rightTree, p);
}
return false;
}
return false;
}
@Override
public Boolean visitConditionalExpression(ConditionalExpressionTree tree, Void p) {
// looking for: (a != null ? a.equals(b) : false)
ExpressionTree cond = tree.getCondition();
ExpressionTree trueExp = tree.getTrueExpression();
ExpressionTree falseExp = tree.getFalseExpression();
if (isNeqNull(cond, left, right) && (falseExp.getKind() == Tree.Kind.BOOLEAN_LITERAL) && ((LiteralTree) falseExp).getValue().equals(false)) {
return visit(trueExp, p);
}
return false;
}
@Override
public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) {
if (!isInvocationOfEquals(tree)) {
return false;
}
List<? extends ExpressionTree> args = tree.getArguments();
if (args.size() != 1) {
return false;
}
ExpressionTree arg = args.get(0);
// if (arg.getKind() != Tree.Kind.IDENTIFIER) {
// return false;
// }
// Element argElt = TreeUtils.elementFromUse((IdentifierTree) arg);
ExpressionTree exp = tree.getMethodSelect();
if (exp.getKind() != Tree.Kind.MEMBER_SELECT) {
return false;
}
MemberSelectTree member = (MemberSelectTree) exp;
ExpressionTree receiver = member.getExpression();
if (TreeUtils.sameTree(receiver, left) && TreeUtils.sameTree(arg, right)) {
return true;
}
if (TreeUtils.sameTree(receiver, right) && TreeUtils.sameTree(arg, left)) {
return true;
}
return false;
}
};
boolean okay = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.CONDITIONAL_OR, matcherEqOrEquals)).match(getCurrentPath());
return okay;
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class InterningVisitor method isReferenceEqualityImplementation.
/**
* Returns true if the given equals() method implements reference equality.
*
* @param equalsMethod an overriding implementation of Object.equals()
* @return true if the given equals() method implements reference equality
*/
private boolean isReferenceEqualityImplementation(MethodTree equalsMethod) {
BlockTree body = equalsMethod.getBody();
List<? extends StatementTree> bodyStatements = body.getStatements();
if (bodyStatements.size() == 1) {
StatementTree bodyStatement = bodyStatements.get(0);
if (bodyStatement.getKind() == Tree.Kind.RETURN) {
ExpressionTree returnExpr = TreeUtils.withoutParens(((ReturnTree) bodyStatement).getExpression());
if (returnExpr.getKind() == Tree.Kind.EQUAL_TO) {
BinaryTree bt = (BinaryTree) returnExpr;
ExpressionTree lhsTree = bt.getLeftOperand();
ExpressionTree rhsTree = bt.getRightOperand();
if (lhsTree.getKind() == Tree.Kind.IDENTIFIER && rhsTree.getKind() == Tree.Kind.IDENTIFIER) {
Name leftName = ((IdentifierTree) lhsTree).getName();
Name rightName = ((IdentifierTree) rhsTree).getName();
Name paramName = equalsMethod.getParameters().get(0).getName();
if ((leftName.contentEquals("this") && rightName == paramName) || (leftName == paramName && rightName.contentEquals("this"))) {
return true;
}
}
}
}
}
return false;
}
use of com.sun.source.tree.BinaryTree in project checker-framework by typetools.
the class CFGTranslationPhaseOne method visitEnhancedForLoop.
@Override
public Node visitEnhancedForLoop(EnhancedForLoopTree tree, Void p) {
// see JLS 14.14.2
Name parentLabel = getLabel(getCurrentPath());
Label conditionStart = new Label();
Label loopEntry = new Label();
Label loopExit = new Label();
// If the loop is a labeled statement, then its continue target is identical for continues with
// no label and continues with the loop's label.
Label updateStart;
if (parentLabel != null) {
updateStart = continueLabels.get(parentLabel);
} else {
updateStart = new Label();
}
TryFinallyScopeCell oldBreakTargetL = breakTargetL;
breakTargetL = new TryFinallyScopeCell(loopExit);
TryFinallyScopeCell oldContinueTargetL = continueTargetL;
continueTargetL = new TryFinallyScopeCell(updateStart);
// Distinguish loops over Iterables from loops over arrays.
VariableTree variable = tree.getVariable();
VariableElement variableElement = TreeUtils.elementFromDeclaration(variable);
ExpressionTree expression = tree.getExpression();
StatementTree statement = tree.getStatement();
TypeMirror exprType = TreeUtils.typeOf(expression);
if (types.isSubtype(exprType, iterableType)) {
// Take the upper bound of a type variable or wildcard
exprType = TypesUtils.upperBound(exprType);
assert (exprType instanceof DeclaredType) : "an Iterable must be a DeclaredType";
DeclaredType declaredExprType = (DeclaredType) exprType;
declaredExprType.getTypeArguments();
MemberSelectTree iteratorSelect = treeBuilder.buildIteratorMethodAccess(expression);
handleArtificialTree(iteratorSelect);
MethodInvocationTree iteratorCall = treeBuilder.buildMethodInvocation(iteratorSelect);
handleArtificialTree(iteratorCall);
VariableTree iteratorVariable = createEnhancedForLoopIteratorVariable(iteratorCall, variableElement);
handleArtificialTree(iteratorVariable);
VariableDeclarationNode iteratorVariableDecl = new VariableDeclarationNode(iteratorVariable);
iteratorVariableDecl.setInSource(false);
extendWithNode(iteratorVariableDecl);
Node expressionNode = scan(expression, p);
MethodAccessNode iteratorAccessNode = new MethodAccessNode(iteratorSelect, expressionNode);
iteratorAccessNode.setInSource(false);
extendWithNode(iteratorAccessNode);
MethodInvocationNode iteratorCallNode = new MethodInvocationNode(iteratorCall, iteratorAccessNode, Collections.emptyList(), getCurrentPath());
iteratorCallNode.setInSource(false);
extendWithNode(iteratorCallNode);
translateAssignment(iteratorVariable, new LocalVariableNode(iteratorVariable), iteratorCallNode);
// Test the loop ending condition
addLabelForNextNode(conditionStart);
IdentifierTree iteratorUse1 = treeBuilder.buildVariableUse(iteratorVariable);
handleArtificialTree(iteratorUse1);
LocalVariableNode iteratorReceiverNode = new LocalVariableNode(iteratorUse1);
iteratorReceiverNode.setInSource(false);
extendWithNode(iteratorReceiverNode);
MemberSelectTree hasNextSelect = treeBuilder.buildHasNextMethodAccess(iteratorUse1);
handleArtificialTree(hasNextSelect);
MethodAccessNode hasNextAccessNode = new MethodAccessNode(hasNextSelect, iteratorReceiverNode);
hasNextAccessNode.setInSource(false);
extendWithNode(hasNextAccessNode);
MethodInvocationTree hasNextCall = treeBuilder.buildMethodInvocation(hasNextSelect);
handleArtificialTree(hasNextCall);
MethodInvocationNode hasNextCallNode = new MethodInvocationNode(hasNextCall, hasNextAccessNode, Collections.emptyList(), getCurrentPath());
hasNextCallNode.setInSource(false);
extendWithNode(hasNextCallNode);
extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
// Loop body, starting with declaration of the loop iteration variable
addLabelForNextNode(loopEntry);
extendWithNode(new VariableDeclarationNode(variable));
IdentifierTree iteratorUse2 = treeBuilder.buildVariableUse(iteratorVariable);
handleArtificialTree(iteratorUse2);
LocalVariableNode iteratorReceiverNode2 = new LocalVariableNode(iteratorUse2);
iteratorReceiverNode2.setInSource(false);
extendWithNode(iteratorReceiverNode2);
MemberSelectTree nextSelect = treeBuilder.buildNextMethodAccess(iteratorUse2);
handleArtificialTree(nextSelect);
MethodAccessNode nextAccessNode = new MethodAccessNode(nextSelect, iteratorReceiverNode2);
nextAccessNode.setInSource(false);
extendWithNode(nextAccessNode);
MethodInvocationTree nextCall = treeBuilder.buildMethodInvocation(nextSelect);
handleArtificialTree(nextCall);
MethodInvocationNode nextCallNode = new MethodInvocationNode(nextCall, nextAccessNode, Collections.emptyList(), getCurrentPath());
// If the type of iteratorVariable is a capture, its type tree may be missing annotations, so
// save the expression in the node so that the full type can be found later.
nextCallNode.setIterableExpression(expression);
nextCallNode.setInSource(false);
extendWithNode(nextCallNode);
AssignmentNode assignNode = translateAssignment(variable, new LocalVariableNode(variable), nextCall);
// translateAssignment() scans variable and creates new nodes, so set the expression
// there, too.
((MethodInvocationNode) assignNode.getExpression()).setIterableExpression(expression);
assert statement != null;
scan(statement, p);
// Loop back edge
addLabelForNextNode(updateStart);
extendWithExtendedNode(new UnconditionalJump(conditionStart));
} else {
// TODO: Shift any labels after the initialization of the
// temporary array variable.
VariableTree arrayVariable = createEnhancedForLoopArrayVariable(expression, variableElement);
handleArtificialTree(arrayVariable);
VariableDeclarationNode arrayVariableNode = new VariableDeclarationNode(arrayVariable);
arrayVariableNode.setInSource(false);
extendWithNode(arrayVariableNode);
Node expressionNode = scan(expression, p);
translateAssignment(arrayVariable, new LocalVariableNode(arrayVariable), expressionNode);
// Declare and initialize the loop index variable
TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
LiteralTree zero = treeBuilder.buildLiteral(Integer.valueOf(0));
handleArtificialTree(zero);
VariableTree indexVariable = treeBuilder.buildVariableDecl(intType, uniqueName("index"), variableElement.getEnclosingElement(), zero);
handleArtificialTree(indexVariable);
VariableDeclarationNode indexVariableNode = new VariableDeclarationNode(indexVariable);
indexVariableNode.setInSource(false);
extendWithNode(indexVariableNode);
IntegerLiteralNode zeroNode = new IntegerLiteralNode(zero);
extendWithNode(zeroNode);
translateAssignment(indexVariable, new LocalVariableNode(indexVariable), zeroNode);
// Compare index to array length
addLabelForNextNode(conditionStart);
IdentifierTree indexUse1 = treeBuilder.buildVariableUse(indexVariable);
handleArtificialTree(indexUse1);
LocalVariableNode indexNode1 = new LocalVariableNode(indexUse1);
indexNode1.setInSource(false);
extendWithNode(indexNode1);
IdentifierTree arrayUse1 = treeBuilder.buildVariableUse(arrayVariable);
handleArtificialTree(arrayUse1);
LocalVariableNode arrayNode1 = new LocalVariableNode(arrayUse1);
extendWithNode(arrayNode1);
MemberSelectTree lengthSelect = treeBuilder.buildArrayLengthAccess(arrayUse1);
handleArtificialTree(lengthSelect);
FieldAccessNode lengthAccessNode = new FieldAccessNode(lengthSelect, arrayNode1);
lengthAccessNode.setInSource(false);
extendWithNode(lengthAccessNode);
BinaryTree lessThan = treeBuilder.buildLessThan(indexUse1, lengthSelect);
handleArtificialTree(lessThan);
LessThanNode lessThanNode = new LessThanNode(lessThan, indexNode1, lengthAccessNode);
lessThanNode.setInSource(false);
extendWithNode(lessThanNode);
extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
// Loop body, starting with declaration of the loop iteration variable
addLabelForNextNode(loopEntry);
extendWithNode(new VariableDeclarationNode(variable));
IdentifierTree arrayUse2 = treeBuilder.buildVariableUse(arrayVariable);
handleArtificialTree(arrayUse2);
LocalVariableNode arrayNode2 = new LocalVariableNode(arrayUse2);
arrayNode2.setInSource(false);
extendWithNode(arrayNode2);
IdentifierTree indexUse2 = treeBuilder.buildVariableUse(indexVariable);
handleArtificialTree(indexUse2);
LocalVariableNode indexNode2 = new LocalVariableNode(indexUse2);
indexNode2.setInSource(false);
extendWithNode(indexNode2);
ArrayAccessTree arrayAccess = treeBuilder.buildArrayAccess(arrayUse2, indexUse2);
handleArtificialTree(arrayAccess);
ArrayAccessNode arrayAccessNode = new ArrayAccessNode(arrayAccess, arrayNode2, indexNode2);
arrayAccessNode.setArrayExpression(expression);
arrayAccessNode.setInSource(false);
extendWithNode(arrayAccessNode);
AssignmentNode arrayAccessAssignNode = translateAssignment(variable, new LocalVariableNode(variable), arrayAccessNode);
extendWithNodeWithException(arrayAccessNode, nullPointerExceptionType);
// translateAssignment() scans variable and creates new nodes, so set the expression
// there, too.
Node arrayAccessAssignNodeExpr = arrayAccessAssignNode.getExpression();
if (arrayAccessAssignNodeExpr instanceof ArrayAccessNode) {
((ArrayAccessNode) arrayAccessAssignNodeExpr).setArrayExpression(expression);
} else if (arrayAccessAssignNodeExpr instanceof MethodInvocationNode) {
// If the array component type is a primitive, there may be a boxing or unboxing
// conversion. Treat that as an iterator.
MethodInvocationNode boxingNode = (MethodInvocationNode) arrayAccessAssignNodeExpr;
boxingNode.setIterableExpression(expression);
}
assert statement != null;
scan(statement, p);
// Loop back edge
addLabelForNextNode(updateStart);
IdentifierTree indexUse3 = treeBuilder.buildVariableUse(indexVariable);
handleArtificialTree(indexUse3);
LocalVariableNode indexNode3 = new LocalVariableNode(indexUse3);
indexNode3.setInSource(false);
extendWithNode(indexNode3);
LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
handleArtificialTree(oneTree);
Node one = new IntegerLiteralNode(oneTree);
one.setInSource(false);
extendWithNode(one);
BinaryTree addOneTree = treeBuilder.buildBinary(intType, Tree.Kind.PLUS, indexUse3, oneTree);
handleArtificialTree(addOneTree);
Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one);
addOneNode.setInSource(false);
extendWithNode(addOneNode);
AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree);
handleArtificialTree(assignTree);
Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode);
assignNode.setInSource(false);
extendWithNode(assignNode);
extendWithExtendedNode(new UnconditionalJump(conditionStart));
}
// Loop exit
addLabelForNextNode(loopExit);
breakTargetL = oldBreakTargetL;
continueTargetL = oldContinueTargetL;
return null;
}
Aggregations