use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class InterningVisitor method suppressInsideComparison.
/**
* Pattern matches particular comparisons to avoid common false positives in the {@link
* Comparable#compareTo(Object)} and {@link Object#equals(Object)}.
*
* <p>Specifically, this method tests if: the comparison is a == comparison, it is the test of an
* if statement that's the first statement in the method, and one of the following is true:
*
* <ol>
* <li>the method overrides {@link Comparator#compare}, the "then" branch of the if statement
* returns zero, and the comparison tests equality of the method's two parameters
* <li>the method overrides {@link Object#equals(Object)} and the comparison tests "this"
* against the method's parameter
* <li>the method overrides {@link Comparable#compareTo(Object)}, the "then" branch of the if
* statement returns zero, and the comparison tests "this" against the method's parameter
* </ol>
*
* @param node the comparison to check
* @return true if one of the supported heuristics is matched, false otherwise
*/
// TODO: handle != comparisons too!
// TODO: handle more methods, such as early return from addAll when this == arg
private boolean suppressInsideComparison(final BinaryTree node) {
// Only handle == binary trees
if (node.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
Tree left = node.getLeftOperand();
Tree right = node.getRightOperand();
// Only valid if we're comparing identifiers.
if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER)) {
return false;
}
TreePath path = getCurrentPath();
TreePath parentPath = path.getParentPath();
Tree parent = parentPath.getLeaf();
// statement in the method.
if (parent.getKind() == Tree.Kind.RETURN) {
// ensure the return statement is the first statement in the method
if (parentPath.getParentPath().getParentPath().getLeaf().getKind() != Tree.Kind.METHOD) {
return false;
}
// maybe set some variables??
} else if (Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) {
// Ensure the if statement is the first statement in the method
// Retrieve the enclosing if statement tree and method tree
Tree ifStatementTree = null;
MethodTree methodTree = null;
// Set ifStatementTree and methodTree
{
TreePath ppath = parentPath;
Tree tree;
while ((tree = ppath.getLeaf()) != null) {
if (tree.getKind() == Tree.Kind.IF) {
ifStatementTree = tree;
} else if (tree.getKind() == Tree.Kind.METHOD) {
methodTree = (MethodTree) tree;
break;
}
ppath = ppath.getParentPath();
}
}
assert ifStatementTree != null;
assert methodTree != null;
StatementTree firstStmnt = methodTree.getBody().getStatements().get(0);
assert firstStmnt != null;
// comparing AST nodes
@SuppressWarnings("interning:not.interned") boolean notSameNode = firstStmnt != ifStatementTree;
if (notSameNode) {
// The if statement is not the first statement in the method.
return false;
}
} else {
return false;
}
ExecutableElement enclosingMethod = TreeUtils.elementFromDeclaration(methodTree);
assert enclosingMethod != null;
final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);
// Matcher to check for if statement that returns zero
Heuristics.Matcher matcherIfReturnsZero = new Heuristics.Matcher() {
@Override
public Boolean visitIf(IfTree tree, Void p) {
return visit(tree.getThenStatement(), p);
}
@Override
public Boolean visitBlock(BlockTree tree, Void p) {
if (tree.getStatements().isEmpty()) {
return false;
}
return visit(tree.getStatements().get(0), p);
}
@Override
public Boolean visitReturn(ReturnTree tree, Void p) {
ExpressionTree expr = tree.getExpression();
return (expr != null && expr.getKind() == Tree.Kind.INT_LITERAL && ((LiteralTree) expr).getValue().equals(0));
}
};
boolean hasCompareToMethodAnno = atypeFactory.getDeclAnnotation(enclosingMethod, CompareToMethod.class) != null;
boolean hasEqualsMethodAnno = atypeFactory.getDeclAnnotation(enclosingMethod, EqualsMethod.class) != null;
int params = enclosingMethod.getParameters().size();
// "return 0" statement (for the Comparator.compare heuristic).
if (overrides(enclosingMethod, Comparator.class, "compare") || (hasCompareToMethodAnno && params == 2)) {
final boolean returnsZero = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert params == 2;
Element p1 = enclosingMethod.getParameters().get(0);
Element p2 = enclosingMethod.getParameters().get(1);
return (p1.equals(lhs) && p2.equals(rhs)) || (p1.equals(rhs) && p2.equals(lhs));
} else if (overrides(enclosingMethod, Object.class, "equals") || (hasEqualsMethodAnno && params == 1)) {
assert params == 1;
Element param = enclosingMethod.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (thisElt.equals(rhs) && param.equals(lhs));
} else if (hasEqualsMethodAnno && params == 2) {
Element p1 = enclosingMethod.getParameters().get(0);
Element p2 = enclosingMethod.getParameters().get(1);
return (p1.equals(lhs) && p2.equals(rhs)) || (p1.equals(rhs) && p2.equals(lhs));
} else if (overrides(enclosingMethod, Comparable.class, "compareTo") || (hasCompareToMethodAnno && params == 1)) {
final boolean returnsZero = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
if (!returnsZero) {
return false;
}
assert params == 1;
Element param = enclosingMethod.getParameters().get(0);
Element thisElt = getThis(trees.getScope(getCurrentPath()));
assert thisElt != null;
return (thisElt.equals(lhs) && param.equals(rhs)) || (thisElt.equals(rhs) && param.equals(lhs));
}
return false;
}
use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class InterningVisitor method suppressEarlyCompareTo.
/**
* Pattern matches to prevent false positives of the form {@code (a == b || a.compareTo(b) == 0)}.
* Returns true iff the given node fits this pattern.
*
* @return true iff the node fits the pattern (a == b || a.compareTo(b) == 0)
*/
private boolean suppressEarlyCompareTo(final BinaryTree node) {
// Only handle == binary trees
if (node.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
Tree left = TreeUtils.withoutParens(node.getLeftOperand());
Tree right = TreeUtils.withoutParens(node.getRightOperand());
// Only valid if we're comparing identifiers.
if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER)) {
return false;
}
final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);
// looking for ((a == b || a.compareTo(b) == 0)
Heuristics.Matcher matcherEqOrCompareTo = new Heuristics.Matcher() {
@Override
public Boolean visitBinary(BinaryTree tree, Void p) {
if (tree.getKind() == Tree.Kind.EQUAL_TO) {
// a.compareTo(b) == 0
// looking for a.compareTo(b) or
ExpressionTree leftTree = tree.getLeftOperand();
// b.compareTo(a)
// looking for 0
ExpressionTree rightTree = tree.getRightOperand();
if (rightTree.getKind() != Tree.Kind.INT_LITERAL) {
return false;
}
LiteralTree rightLiteral = (LiteralTree) rightTree;
if (!rightLiteral.getValue().equals(0)) {
return false;
}
return visit(leftTree, p);
} else {
// a == b || a.compareTo(b) == 0
@// AST node comparisons
SuppressWarnings(// AST node comparisons
"interning:assignment") @InternedDistinct ExpressionTree // looking for a==b
leftTree = tree.getLeftOperand();
// looking for a.compareTo(b) == 0
ExpressionTree rightTree = tree.getRightOperand();
// or b.compareTo(a) == 0
if (leftTree != node) {
return false;
}
if (rightTree.getKind() != Tree.Kind.EQUAL_TO) {
return false;
}
return visit(rightTree, p);
}
}
@Override
public Boolean visitMethodInvocation(MethodInvocationTree tree, Void p) {
if (!TreeUtils.isMethodInvocation(tree, comparableCompareTo, checker.getProcessingEnvironment())) {
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(arg);
ExpressionTree exp = tree.getMethodSelect();
if (exp.getKind() != Tree.Kind.MEMBER_SELECT) {
return false;
}
MemberSelectTree member = (MemberSelectTree) exp;
if (member.getExpression().getKind() != Tree.Kind.IDENTIFIER) {
return false;
}
Element refElt = TreeUtils.elementFromUse(member.getExpression());
if (!((refElt.equals(lhs) && argElt.equals(rhs)) || (refElt.equals(rhs) && argElt.equals(lhs)))) {
return false;
}
return true;
}
};
boolean okay = new Heuristics.Within(new Heuristics.OfKind(Tree.Kind.CONDITIONAL_OR, matcherEqOrCompareTo)).match(getCurrentPath());
return okay;
}
use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class NullnessVisitor method isNewArrayInToArray.
/**
* Return true if the given node is "new X[]", in the context "toArray(new X[])".
*
* @param node a node to test
* @return true if the node is a new array within acall to toArray()
*/
private boolean isNewArrayInToArray(NewArrayTree node) {
if (node.getDimensions().size() != 1) {
return false;
}
ExpressionTree dim = node.getDimensions().get(0);
ProcessingEnvironment env = checker.getProcessingEnvironment();
if (!TreeUtils.isMethodInvocation(dim, collectionSize, env)) {
return false;
}
ExpressionTree rcvsize = ((MethodInvocationTree) dim).getMethodSelect();
if (!(rcvsize instanceof MemberSelectTree)) {
return false;
}
rcvsize = ((MemberSelectTree) rcvsize).getExpression();
if (!(rcvsize instanceof IdentifierTree)) {
return false;
}
Tree encl = getCurrentPath().getParentPath().getLeaf();
if (!TreeUtils.isMethodInvocation(encl, collectionToArray, env)) {
return false;
}
ExpressionTree rcvtoarray = ((MethodInvocationTree) encl).getMethodSelect();
if (!(rcvtoarray instanceof MemberSelectTree)) {
return false;
}
rcvtoarray = ((MemberSelectTree) rcvtoarray).getExpression();
if (!(rcvtoarray instanceof IdentifierTree)) {
return false;
}
return ((IdentifierTree) rcvsize).getName() == ((IdentifierTree) rcvtoarray).getName();
}
use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class MustCallTransfer method getOrCreateTempVar.
/**
* Either returns the temporary variable associated with node, or creates one if one does not
* exist.
*
* @param node a node, which must be an expression (not a statement)
* @return a temporary variable node representing {@code node} that can be placed into a store
*/
@Nullable
private LocalVariableNode getOrCreateTempVar(Node node) {
LocalVariableNode localVariableNode = atypeFactory.tempVars.get(node.getTree());
if (localVariableNode == null) {
VariableTree temp = createTemporaryVar(node);
if (temp != null) {
IdentifierTree identifierTree = treeBuilder.buildVariableUse(temp);
localVariableNode = new LocalVariableNode(identifierTree);
localVariableNode.setInSource(true);
atypeFactory.tempVars.put(node.getTree(), localVariableNode);
}
}
return localVariableNode;
}
use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class TreeParserTest method parsesMethodInvocations.
@Test
public void parsesMethodInvocations() {
String value = "test()";
ExpressionTree parsed = parser.parseTree(value);
Assert.assertTrue(parsed instanceof MethodInvocationTree);
MethodInvocationTree invocation = (MethodInvocationTree) parsed;
Assert.assertTrue(invocation.getMethodSelect() instanceof IdentifierTree);
Assert.assertEquals("test", ((IdentifierTree) invocation.getMethodSelect()).getName().toString());
}
Aggregations