Search in sources :

Example 66 with IdentifierTree

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;
}
Also used : MethodTree(com.sun.source.tree.MethodTree) Heuristics(org.checkerframework.framework.util.Heuristics) ExecutableElement(javax.lang.model.element.ExecutableElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) EqualsMethod(org.checkerframework.checker.interning.qual.EqualsMethod) ReturnTree(com.sun.source.tree.ReturnTree) IfTree(com.sun.source.tree.IfTree) Comparator(java.util.Comparator) StatementTree(com.sun.source.tree.StatementTree) TreePath(com.sun.source.util.TreePath) CompareToMethod(org.checkerframework.checker.interning.qual.CompareToMethod) ReturnTree(com.sun.source.tree.ReturnTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewClassTree(com.sun.source.tree.NewClassTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) IfTree(com.sun.source.tree.IfTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) BlockTree(com.sun.source.tree.BlockTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 67 with IdentifierTree

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;
}
Also used : Heuristics(org.checkerframework.framework.util.Heuristics) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) MemberSelectTree(com.sun.source.tree.MemberSelectTree) BinaryTree(com.sun.source.tree.BinaryTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) InternedDistinct(org.checkerframework.checker.interning.qual.InternedDistinct) ReturnTree(com.sun.source.tree.ReturnTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewClassTree(com.sun.source.tree.NewClassTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) IfTree(com.sun.source.tree.IfTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 68 with IdentifierTree

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();
}
Also used : MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) IdentifierTree(com.sun.source.tree.IdentifierTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) LiteralTree(com.sun.source.tree.LiteralTree) AnnotatedTypeTree(com.sun.source.tree.AnnotatedTypeTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) TypeCastTree(com.sun.source.tree.TypeCastTree) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) NewArrayTree(com.sun.source.tree.NewArrayTree) ForLoopTree(com.sun.source.tree.ForLoopTree) InstanceOfTree(com.sun.source.tree.InstanceOfTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) SwitchTree(com.sun.source.tree.SwitchTree) ThrowTree(com.sun.source.tree.ThrowTree) SynchronizedTree(com.sun.source.tree.SynchronizedTree) AssertTree(com.sun.source.tree.AssertTree) WhileLoopTree(com.sun.source.tree.WhileLoopTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ArrayTypeTree(com.sun.source.tree.ArrayTypeTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) IfTree(com.sun.source.tree.IfTree) ExpressionTree(com.sun.source.tree.ExpressionTree) DoWhileLoopTree(com.sun.source.tree.DoWhileLoopTree) ProcessingEnvironment(javax.annotation.processing.ProcessingEnvironment)

Example 69 with IdentifierTree

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;
}
Also used : VariableTree(com.sun.source.tree.VariableTree) IdentifierTree(com.sun.source.tree.IdentifierTree) LocalVariableNode(org.checkerframework.dataflow.cfg.node.LocalVariableNode) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 70 with IdentifierTree

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());
}
Also used : MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Test(org.junit.Test)

Aggregations

IdentifierTree (com.sun.source.tree.IdentifierTree)82 ExpressionTree (com.sun.source.tree.ExpressionTree)41 MemberSelectTree (com.sun.source.tree.MemberSelectTree)36 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)28 Element (javax.lang.model.element.Element)24 Tree (com.sun.source.tree.Tree)21 ExecutableElement (javax.lang.model.element.ExecutableElement)18 VariableTree (com.sun.source.tree.VariableTree)17 TypeElement (javax.lang.model.element.TypeElement)16 MethodTree (com.sun.source.tree.MethodTree)13 VariableElement (javax.lang.model.element.VariableElement)13 ClassTree (com.sun.source.tree.ClassTree)12 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)11 ArrayAccessTree (com.sun.source.tree.ArrayAccessTree)10 NewClassTree (com.sun.source.tree.NewClassTree)10 AssignmentTree (com.sun.source.tree.AssignmentTree)9 BinaryTree (com.sun.source.tree.BinaryTree)9 LiteralTree (com.sun.source.tree.LiteralTree)8 StatementTree (com.sun.source.tree.StatementTree)8 Symbol (com.sun.tools.javac.code.Symbol)8