Search in sources :

Example 11 with LiteralTree

use of com.sun.source.tree.LiteralTree in project error-prone by google.

the class PreconditionsInvalidPlaceholder method describe.

public Description describe(MethodInvocationTree t, VisitorState state) {
    LiteralTree formatTree = (LiteralTree) t.getArguments().get(1);
    String fixedFormatString = BAD_PLACEHOLDER_REGEX.matcher(state.getSourceForNode((JCTree) formatTree)).replaceAll("%s");
    if (expectedArguments(fixedFormatString) == t.getArguments().size() - 2) {
        return describeMatch(formatTree, SuggestedFix.replace(formatTree, fixedFormatString));
    } else {
        int missing = t.getArguments().size() - 2 - expectedArguments(fixedFormatString);
        StringBuilder builder = new StringBuilder(fixedFormatString);
        builder.deleteCharAt(builder.length() - 1);
        builder.append(" [%s");
        for (int i = 1; i < missing; i++) {
            builder.append(", %s");
        }
        builder.append("]\"");
        return describeMatch(t, SuggestedFix.replace(formatTree, builder.toString()));
    }
}
Also used : LiteralTree(com.sun.source.tree.LiteralTree)

Example 12 with LiteralTree

use of com.sun.source.tree.LiteralTree in project checker-framework by typetools.

the class FlowExpressions method internalReprOf.

/**
 * We ignore operations such as widening and narrowing when computing the internal
 * representation.
 *
 * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}.
 *     Might contain {@link Unknown}.
 */
public static Receiver internalReprOf(AnnotationProvider provider, ExpressionTree receiverTree, boolean allowNonDeterministic) {
    Receiver receiver;
    switch(receiverTree.getKind()) {
        case ARRAY_ACCESS:
            ArrayAccessTree a = (ArrayAccessTree) receiverTree;
            Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression());
            Receiver index = internalReprOf(provider, a.getIndex());
            receiver = 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) receiverTree;
            receiver = new ValueLiteral(TreeUtils.typeOf(receiverTree), vn.getValue());
            break;
        case NEW_ARRAY:
            NewArrayTree newArrayTree = (NewArrayTree) receiverTree;
            List<Receiver> dimensions = new ArrayList<>();
            if (newArrayTree.getDimensions() != null) {
                for (ExpressionTree dimension : newArrayTree.getDimensions()) {
                    dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic));
                }
            }
            List<Receiver> initializers = new ArrayList<>();
            if (newArrayTree.getInitializers() != null) {
                for (ExpressionTree initializer : newArrayTree.getInitializers()) {
                    initializers.add(internalReprOf(provider, initializer, allowNonDeterministic));
                }
            }
            receiver = new ArrayCreation(TreeUtils.typeOf(receiverTree), dimensions, initializers);
            break;
        case METHOD_INVOCATION:
            MethodInvocationTree mn = (MethodInvocationTree) receiverTree;
            ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn);
            if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) {
                List<Receiver> parameters = new ArrayList<>();
                for (ExpressionTree p : mn.getArguments()) {
                    parameters.add(internalReprOf(provider, p));
                }
                Receiver methodReceiver;
                if (ElementUtils.isStatic(invokedMethod)) {
                    methodReceiver = new ClassName(TreeUtils.typeOf(mn.getMethodSelect()));
                } else {
                    ExpressionTree methodReceiverTree = TreeUtils.getReceiverTree(mn);
                    if (methodReceiverTree != null) {
                        methodReceiver = internalReprOf(provider, methodReceiverTree);
                    } else {
                        methodReceiver = internalReprOfImplicitReceiver(invokedMethod);
                    }
                }
                TypeMirror type = TreeUtils.typeOf(mn);
                receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters);
            } else {
                receiver = null;
            }
            break;
        case MEMBER_SELECT:
            receiver = internalReprOfMemberSelect(provider, (MemberSelectTree) receiverTree);
            break;
        case IDENTIFIER:
            IdentifierTree identifierTree = (IdentifierTree) receiverTree;
            TypeMirror typeOfId = TreeUtils.typeOf(identifierTree);
            if (identifierTree.getName().contentEquals("this") || identifierTree.getName().contentEquals("super")) {
                receiver = new ThisReference(typeOfId);
                break;
            }
            Element ele = TreeUtils.elementFromUse(identifierTree);
            switch(ele.getKind()) {
                case LOCAL_VARIABLE:
                case RESOURCE_VARIABLE:
                case EXCEPTION_PARAMETER:
                case PARAMETER:
                    receiver = new LocalVariable(ele);
                    break;
                case FIELD:
                    // Implicit access expression, such as "this" or a class name
                    Receiver fieldAccessExpression;
                    TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType();
                    if (ElementUtils.isStatic(ele)) {
                        fieldAccessExpression = new ClassName(enclosingType);
                    } else {
                        fieldAccessExpression = new ThisReference(enclosingType);
                    }
                    receiver = new FieldAccess(fieldAccessExpression, typeOfId, (VariableElement) ele);
                    break;
                case CLASS:
                case ENUM:
                case ANNOTATION_TYPE:
                case INTERFACE:
                    receiver = new ClassName(ele.asType());
                    break;
                default:
                    receiver = null;
            }
            break;
        default:
            receiver = null;
    }
    if (receiver == null) {
        receiver = new Unknown(TreeUtils.typeOf(receiverTree));
    }
    return receiver;
}
Also used : ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) ExecutableElement(javax.lang.model.element.ExecutableElement) MemberSelectTree(com.sun.source.tree.MemberSelectTree) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) ArrayList(java.util.ArrayList) IdentifierTree(com.sun.source.tree.IdentifierTree) VariableElement(javax.lang.model.element.VariableElement) LiteralTree(com.sun.source.tree.LiteralTree) NewArrayTree(com.sun.source.tree.NewArrayTree) TypeMirror(javax.lang.model.type.TypeMirror) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 13 with LiteralTree

use of com.sun.source.tree.LiteralTree 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.skipParens(node.getLeftOperand());
    Tree right = TreeUtils.skipParens(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
                ExpressionTree leftTree = // looking for a.compareTo(b) or
                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
                // looking for a==b
                ExpressionTree leftTree = tree.getLeftOperand();
                ExpressionTree rightTree = // looking for a.compareTo(b) == 0
                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 (!isInvocationOfCompareTo(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(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 = Heuristics.Matchers.withIn(Heuristics.Matchers.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) 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) 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 14 with LiteralTree

use of com.sun.source.tree.LiteralTree 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;
    // parens and blocks), terminate.
    if (!Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) {
        return false;
    }
    // Ensure the if statement is the first statement in the method
    TreePath parentPath = getCurrentPath().getParentPath();
    // Retrieve the enclosing if statement tree and method tree
    Tree tree, ifStatementTree = null;
    MethodTree methodTree = null;
    while ((tree = parentPath.getLeaf()) != null) {
        if (tree.getKind() == Tree.Kind.IF) {
            ifStatementTree = tree;
        } else if (tree.getKind() == Tree.Kind.METHOD) {
            methodTree = (MethodTree) tree;
            break;
        }
        parentPath = parentPath.getParentPath();
    }
    // The call to Heuristics.matchParents already ensured there is an enclosing if statement
    assert ifStatementTree != null;
    // The call to Heuristics.matchParents already ensured there is an enclosing method
    assert methodTree != null;
    StatementTree stmnt = methodTree.getBody().getStatements().get(0);
    // The call to Heuristics.matchParents already ensured the enclosing method has at least one statement (an if statement) in the body
    assert stmnt != null;
    if (stmnt != ifStatementTree) {
        // The if statement is not the first statement in the method.
        return false;
    }
    ExecutableElement enclosing = TreeUtils.elementFromDeclaration(visitorState.getMethodTree());
    assert enclosing != 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().size() > 0) {
                return visit(tree.getStatements().get(0), p);
            }
            return false;
        }

        @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));
        }
    };
    // "return 0" statement (for the Comparator.compare heuristic).
    if (overrides(enclosing, Comparator.class, "compare")) {
        final boolean returnsZero = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
        if (!returnsZero) {
            return false;
        }
        assert enclosing.getParameters().size() == 2;
        Element p1 = enclosing.getParameters().get(0);
        Element p2 = enclosing.getParameters().get(1);
        return (p1.equals(lhs) && p2.equals(rhs)) || (p2.equals(lhs) && p1.equals(rhs));
    } else if (overrides(enclosing, Object.class, "equals")) {
        assert enclosing.getParameters().size() == 1;
        Element param = enclosing.getParameters().get(0);
        Element thisElt = getThis(trees.getScope(getCurrentPath()));
        assert thisElt != null;
        return (thisElt.equals(lhs) && param.equals(rhs)) || (param.equals(lhs) && thisElt.equals(rhs));
    } else if (overrides(enclosing, Comparable.class, "compareTo")) {
        final boolean returnsZero = Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcherIfReturnsZero)).match(getCurrentPath());
        if (!returnsZero) {
            return false;
        }
        assert enclosing.getParameters().size() == 1;
        Element param = enclosing.getParameters().get(0);
        Element thisElt = getThis(trees.getScope(getCurrentPath()));
        assert thisElt != null;
        return (thisElt.equals(lhs) && param.equals(rhs)) || (param.equals(lhs) && thisElt.equals(rhs));
    }
    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) ReturnTree(com.sun.source.tree.ReturnTree) IfTree(com.sun.source.tree.IfTree) StatementTree(com.sun.source.tree.StatementTree) TreePath(com.sun.source.util.TreePath) 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) 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 15 with LiteralTree

use of com.sun.source.tree.LiteralTree in project checker-framework by typetools.

the class RegexVisitor method visitMethodInvocation.

/**
 * Case 1: Don't require a Regex annotation on the String argument to Pattern.compile if the
 * Pattern.LITERAL flag is passed.
 */
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
    ProcessingEnvironment env = checker.getProcessingEnvironment();
    if (TreeUtils.isMethodInvocation(node, patternCompile, env)) {
        ExpressionTree flagParam = node.getArguments().get(1);
        if (flagParam.getKind() == Kind.MEMBER_SELECT) {
            MemberSelectTree memSelect = (MemberSelectTree) flagParam;
            if (TreeUtils.isSpecificFieldAccess(memSelect, patternLiteral)) {
                // This is a call to Pattern.compile with the Pattern.LITERAL
                // flag so the first parameter doesn't need to be a
                // @Regex String. Don't call the super method to skip checking
                // if the first parameter is a @Regex String, but make sure to
                // still recurse on all of the different parts of the method call.
                Void r = scan(node.getTypeArguments(), p);
                r = reduce(scan(node.getMethodSelect(), p), r);
                r = reduce(scan(node.getArguments(), p), r);
                return r;
            }
        }
    } else if (TreeUtils.isMethodInvocation(node, matchResultEnd, env) || TreeUtils.isMethodInvocation(node, matchResultGroup, env) || TreeUtils.isMethodInvocation(node, matchResultStart, env)) {
        /**
         * Case 3: Checks calls to {@code MatchResult.start}, {@code MatchResult.end} and {@code
         * MatchResult.group} to ensure that a valid group number is passed.
         */
        ExpressionTree group = node.getArguments().get(0);
        if (group.getKind() == Kind.INT_LITERAL) {
            LiteralTree literal = (LiteralTree) group;
            int paramGroups = (Integer) literal.getValue();
            ExpressionTree receiver = TreeUtils.getReceiverTree(node);
            if (receiver == null) {
                // is out of the scope of this checker.
                return super.visitMethodInvocation(node, p);
            }
            int annoGroups = 0;
            AnnotatedTypeMirror receiverType = atypeFactory.getAnnotatedType(receiver);
            if (receiverType != null && receiverType.hasAnnotation(Regex.class)) {
                annoGroups = atypeFactory.getGroupCount(receiverType.getAnnotation(Regex.class));
            }
            if (paramGroups > annoGroups) {
                checker.report(Result.failure("group.count.invalid", paramGroups, annoGroups, receiver), group);
            }
        } else {
            checker.report(Result.warning("group.count.unknown"), group);
        }
    }
    return super.visitMethodInvocation(node, p);
}
Also used : Regex(org.checkerframework.checker.regex.qual.Regex) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ExpressionTree(com.sun.source.tree.ExpressionTree) ProcessingEnvironment(javax.annotation.processing.ProcessingEnvironment) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) LiteralTree(com.sun.source.tree.LiteralTree)

Aggregations

LiteralTree (com.sun.source.tree.LiteralTree)20 ExpressionTree (com.sun.source.tree.ExpressionTree)13 Tree (com.sun.source.tree.Tree)8 BinaryTree (com.sun.source.tree.BinaryTree)7 MemberSelectTree (com.sun.source.tree.MemberSelectTree)7 IdentifierTree (com.sun.source.tree.IdentifierTree)6 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)6 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)5 PrimitiveTypeTree (com.sun.source.tree.PrimitiveTypeTree)4 TypeCastTree (com.sun.source.tree.TypeCastTree)4 ArrayAccessTree (com.sun.source.tree.ArrayAccessTree)3 BlockTree (com.sun.source.tree.BlockTree)3 ClassTree (com.sun.source.tree.ClassTree)3 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)3 Element (javax.lang.model.element.Element)3 ExecutableElement (javax.lang.model.element.ExecutableElement)3 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)2 AnnotatedTypeTree (com.sun.source.tree.AnnotatedTypeTree)2 IfTree (com.sun.source.tree.IfTree)2 MethodTree (com.sun.source.tree.MethodTree)2