Search in sources :

Example 66 with ExpressionTree

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

the class ChainingConstructorIgnoresParameter method evaluateCallers.

private Description evaluateCallers(MethodSymbol symbol) {
    List<VariableTree> paramTypes = paramTypesForMethod.get(symbol);
    if (paramTypes == null) {
        // We haven't seen the declaration yet. We'll evaluate the call when we do.
        return NO_MATCH;
    }
    for (Caller caller : callersToEvaluate.removeAll(symbol)) {
        VisitorState state = caller.state;
        MethodInvocationTree invocation = caller.tree;
        MethodTree callerConstructor = state.findEnclosing(MethodTree.class);
        if (callerConstructor == null) {
            // impossible, at least in compilable code?
            continue;
        }
        Map<String, Type> availableParams = indexTypeByName(callerConstructor.getParameters());
        /*
       * TODO(cpovirk): Better handling of varargs: If the last parameter type is varargs and it is
       * called as varargs (rather than by passing an array), then rewrite the parameter types to
       * (p0, p1, ..., p[n-2], p[n-1] = element type of varargs parameter if an argument is
       * supplied, p[n] = ditto, etc.). For now, we settle for not crashing in the face of a
       * mismatch between the number of parameters declared and the number supplied.
       *
       * (Use MethodSymbol.isVarArgs.)
       */
        for (int i = 0; i < paramTypes.size() && i < invocation.getArguments().size(); i++) {
            VariableTree formalParam = paramTypes.get(i);
            String formalParamName = formalParam.getName().toString();
            Type formalParamType = getType(formalParam.getType());
            Type availableParamType = availableParams.get(formalParamName);
            ExpressionTree actualParam = invocation.getArguments().get(i);
            if (/*
             * The caller has no param of this type. (Or if it did, we couldn't determine the type.
             * Does that ever happen?) If the param doesn't exist, the caller can't be failing to
             * pass it.
             */
            availableParamType == null || /*
             * We couldn't determine the type of the formal parameter. (Does this ever happen?)
             */
            formalParamType == null || /*
             * The caller is passing the expected parameter (or "ImmutableList.copyOf(parameter),"
             * "new File(parameter)," etc.).
             */
            referencesIdentifierWithName(formalParamName, actualParam, state)) {
                continue;
            }
            if (state.getTypes().isAssignable(availableParamType, formalParamType)) {
                reportMatch(invocation, state, actualParam, formalParamName);
            }
        /*
         * If formal parameter is of an incompatible type, the caller might in theory still intend
         * to pass a dervied expression. For example, "Foo(String file)" might intend to call
         * "Foo(File file)" by passing "new File(file)." If this comes up in practice, we could
         * provide the dummy suggested fix "someExpression(formalParamName)." However, my research
         * suggests that this will rarely if ever be what the user wants.
         */
        }
    }
    // All matches are reported through reportMatch calls instead of return values.
    return NO_MATCH;
}
Also used : ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) Type(com.sun.tools.javac.code.Type) VisitorState(com.google.errorprone.VisitorState) MethodTree(com.sun.source.tree.MethodTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) VariableTree(com.sun.source.tree.VariableTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 67 with ExpressionTree

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

the class ComparisonContractViolated method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    if (tree.getBody() == null) {
        return Description.NO_MATCH;
    }
    // Test that the match is in a Comparable.compareTo or Comparator.compare method.
    ClassTree declaringClass = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
    if (!COMPARABLE_CLASS_MATCHER.matches(declaringClass, state) && !COMPARATOR_CLASS_MATCHER.matches(declaringClass, state)) {
        return Description.NO_MATCH;
    }
    if (!COMPARABLE_METHOD_MATCHER.matches(tree, state) && !COMPARATOR_METHOD_MATCHER.matches(tree, state)) {
        return Description.NO_MATCH;
    }
    final Set<ComparisonResult> seenResults = EnumSet.noneOf(ComparisonResult.class);
    final TreeVisitor<Void, VisitorState> visitReturnExpression = new SimpleTreeVisitor<Void, VisitorState>() {

        @Override
        protected Void defaultAction(Tree node, VisitorState state) {
            seenResults.add(node.accept(CONSTANT_VISITOR, state));
            return null;
        }

        @Override
        public Void visitConditionalExpression(ConditionalExpressionTree node, VisitorState state) {
            node.getTrueExpression().accept(this, state);
            node.getFalseExpression().accept(this, state);
            return null;
        }
    };
    tree.getBody().accept(new TreeScanner<Void, VisitorState>() {

        @Override
        public Void visitReturn(ReturnTree node, VisitorState state) {
            return node.getExpression().accept(visitReturnExpression, state);
        }
    }, state);
    if (seenResults.isEmpty() || seenResults.contains(ComparisonResult.NONCONSTANT)) {
        return Description.NO_MATCH;
    }
    if (!seenResults.contains(ComparisonResult.ZERO)) {
        if (tree.getBody().getStatements().size() == 1 && tree.getBody().getStatements().get(0).getKind() == Kind.RETURN) {
            ReturnTree returnTree = (ReturnTree) tree.getBody().getStatements().get(0);
            if (returnTree.getExpression().getKind() == Kind.CONDITIONAL_EXPRESSION) {
                ConditionalExpressionTree condTree = (ConditionalExpressionTree) returnTree.getExpression();
                ExpressionTree conditionExpr = condTree.getCondition();
                while (conditionExpr instanceof ParenthesizedTree) {
                    conditionExpr = ((ParenthesizedTree) conditionExpr).getExpression();
                }
                if (!(conditionExpr instanceof BinaryTree)) {
                    return describeMatch(tree);
                }
                ComparisonResult trueConst = condTree.getTrueExpression().accept(CONSTANT_VISITOR, state);
                ComparisonResult falseConst = condTree.getFalseExpression().accept(CONSTANT_VISITOR, state);
                boolean trueFirst;
                if (trueConst == ComparisonResult.NEGATIVE_CONSTANT && falseConst == ComparisonResult.POSITIVE_CONSTANT) {
                    trueFirst = true;
                } else if (trueConst == ComparisonResult.POSITIVE_CONSTANT && falseConst == ComparisonResult.NEGATIVE_CONSTANT) {
                    trueFirst = false;
                } else {
                    return describeMatch(tree);
                }
                switch(conditionExpr.getKind()) {
                    case LESS_THAN:
                    case LESS_THAN_EQUAL:
                        break;
                    case GREATER_THAN:
                    case GREATER_THAN_EQUAL:
                        trueFirst = !trueFirst;
                        break;
                    default:
                        return describeMatch(tree);
                }
                BinaryTree binaryExpr = (BinaryTree) conditionExpr;
                Type ty = ASTHelpers.getType(binaryExpr.getLeftOperand());
                Types types = Types.instance(state.context);
                Symtab symtab = Symtab.instance(state.context);
                ExpressionTree first = trueFirst ? binaryExpr.getLeftOperand() : binaryExpr.getRightOperand();
                ExpressionTree second = trueFirst ? binaryExpr.getRightOperand() : binaryExpr.getLeftOperand();
                String compareType;
                if (types.isSameType(ty, symtab.intType)) {
                    compareType = "Integer";
                } else if (types.isSameType(ty, symtab.longType)) {
                    compareType = "Long";
                } else {
                    return describeMatch(tree);
                }
                return describeMatch(condTree, SuggestedFix.replace(condTree, String.format("%s.compare(%s, %s)", compareType, state.getSourceForNode(first), state.getSourceForNode(second))));
            }
        }
        return describeMatch(tree);
    }
    if (COMPARATOR_METHOD_MATCHER.matches(tree, state) && (seenResults.contains(ComparisonResult.NEGATIVE_CONSTANT) != seenResults.contains(ComparisonResult.POSITIVE_CONSTANT))) {
        // See e.g. com.google.common.collect.Cut.BelowAll.
        return describeMatch(tree);
    } else {
        return Description.NO_MATCH;
    }
}
Also used : Types(com.sun.tools.javac.code.Types) SimpleTreeVisitor(com.sun.source.util.SimpleTreeVisitor) ClassTree(com.sun.source.tree.ClassTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) BinaryTree(com.sun.source.tree.BinaryTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ReturnTree(com.sun.source.tree.ReturnTree) Symtab(com.sun.tools.javac.code.Symtab) Type(com.sun.tools.javac.code.Type) VisitorState(com.google.errorprone.VisitorState) ReturnTree(com.sun.source.tree.ReturnTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 68 with ExpressionTree

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

the class ComparisonOutOfRange method describe.

/**
   * Suggested fixes are as follows.  For the byte case, convert the literal to its byte
   * representation. For example, "255" becomes "-1.  For the character case, replace the
   * comparison with "true"/"false" since it's not clear what was intended and that is
   * semantically equivalent.
   *
   * TODO(eaftan): Suggested fixes don't handle side-effecting expressions, such as
   * (d = reader.read()) == -1.  Maybe add special case handling for assignments.
   */
public Description describe(BinaryTree tree, VisitorState state) {
    List<ExpressionTree> binaryTreeMatches = ASTHelpers.matchBinaryTree(tree, Arrays.asList(Matchers.<ExpressionTree>isInstance(JCLiteral.class), Matchers.<ExpressionTree>anything()), state);
    if (binaryTreeMatches == null) {
        throw new IllegalStateException("Expected one of the operands to be a literal");
    }
    JCLiteral literal = (JCLiteral) binaryTreeMatches.get(0);
    JCTree nonLiteralOperand = (JCTree) binaryTreeMatches.get(1);
    boolean byteMatch = state.getTypes().isSameType(nonLiteralOperand.type, state.getSymtab().byteType);
    boolean willEvaluateTo = (tree.getKind() != Kind.EQUAL_TO);
    Fix fix;
    String customDiagnosticMessage;
    if (byteMatch) {
        String replacement = Byte.toString(((Number) literal.getValue()).byteValue());
        // Correct for poor javac 6 literal parsing.
        int actualStart = ASTHelpers.getActualStartPosition(literal, state.getSourceCode());
        if (actualStart != literal.getStartPosition()) {
            fix = SuggestedFix.replace(literal, replacement, actualStart - literal.getStartPosition(), 0);
        } else {
            fix = SuggestedFix.replace(literal, replacement);
        }
        customDiagnosticMessage = String.format(MESSAGE_TEMPLATE, "byte", (int) Byte.MIN_VALUE, (int) Byte.MAX_VALUE, literal.toString(), Boolean.toString(willEvaluateTo));
    } else {
        fix = SuggestedFix.replace(tree, Boolean.toString(willEvaluateTo));
        customDiagnosticMessage = String.format(MESSAGE_TEMPLATE, "char", (int) Character.MIN_VALUE, (int) Character.MAX_VALUE, literal.toString(), Boolean.toString(willEvaluateTo));
    }
    return buildDescription(tree).addFix(fix).setMessage(customDiagnosticMessage).build();
}
Also used : SuggestedFix(com.google.errorprone.fixes.SuggestedFix) Fix(com.google.errorprone.fixes.Fix) ExpressionTree(com.sun.source.tree.ExpressionTree) JCLiteral(com.sun.tools.javac.tree.JCTree.JCLiteral) JCTree(com.sun.tools.javac.tree.JCTree)

Example 69 with ExpressionTree

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

the class ConstantOverflow method longFix.

/**
   * If the left operand of an int binary expression is an int literal, suggest making it a long.
   */
private Fix longFix(ExpressionTree expr, VisitorState state) {
    BinaryTree binExpr = null;
    while (expr instanceof BinaryTree) {
        binExpr = (BinaryTree) expr;
        expr = binExpr.getLeftOperand();
    }
    if (!(expr instanceof LiteralTree) || expr.getKind() != Kind.INT_LITERAL) {
        return null;
    }
    Type intType = state.getSymtab().intType;
    if (!isSameType(getType(binExpr), intType, state)) {
        return null;
    }
    SuggestedFix.Builder fix = SuggestedFix.builder().postfixWith(expr, "L");
    Tree parent = state.getPath().getParentPath().getLeaf();
    if (parent instanceof VariableTree && isSameType(getType(parent), intType, state)) {
        fix.replace(((VariableTree) parent).getType(), "long");
    }
    return fix.build();
}
Also used : ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) ASTHelpers.isSameType(com.google.errorprone.util.ASTHelpers.isSameType) Type(com.sun.tools.javac.code.Type) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) BinaryTree(com.sun.source.tree.BinaryTree) VariableTree(com.sun.source.tree.VariableTree) LiteralTree(com.sun.source.tree.LiteralTree) BinaryTree(com.sun.source.tree.BinaryTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) TypeCastTree(com.sun.source.tree.TypeCastTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) PrimitiveTypeTree(com.sun.source.tree.PrimitiveTypeTree) LiteralTree(com.sun.source.tree.LiteralTree)

Example 70 with ExpressionTree

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

the class DefaultCharset method handleFileWriter.

private Description handleFileWriter(NewClassTree tree, VisitorState state) {
    Iterator<? extends ExpressionTree> it = tree.getArguments().iterator();
    Tree fileArg = it.next();
    Tree appendMode = it.hasNext() ? it.next() : null;
    Tree parent = state.getPath().getParentPath().getLeaf();
    Tree toReplace = BUFFERED_WRITER.matches(parent, state) ? parent : tree;
    Description.Builder description = buildDescription(tree);
    boolean useGuava = shouldUseGuava(state);
    for (CharsetFix charset : CharsetFix.values()) {
        if (appendMode == null && useGuava) {
            description.addFix(guavaFileWriterFix(state, fileArg, toReplace, charset));
        } else {
            description.addFix(nioFileWriterFix(state, appendMode, fileArg, toReplace, charset, useGuava));
        }
    }
    return description.build();
}
Also used : Description(com.google.errorprone.matchers.Description) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) NewClassTree(com.sun.source.tree.NewClassTree) ImportTree(com.sun.source.tree.ImportTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) JCTree(com.sun.tools.javac.tree.JCTree)

Aggregations

ExpressionTree (com.sun.source.tree.ExpressionTree)78 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)27 Tree (com.sun.source.tree.Tree)18 Type (com.sun.tools.javac.code.Type)18 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)16 Symbol (com.sun.tools.javac.code.Symbol)14 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)14 JCTree (com.sun.tools.javac.tree.JCTree)14 Fix (com.google.errorprone.fixes.Fix)13 VariableTree (com.sun.source.tree.VariableTree)13 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)13 IdentifierTree (com.sun.source.tree.IdentifierTree)12 MemberSelectTree (com.sun.source.tree.MemberSelectTree)12 VarSymbol (com.sun.tools.javac.code.Symbol.VarSymbol)11 VisitorState (com.google.errorprone.VisitorState)9 AssignmentTree (com.sun.source.tree.AssignmentTree)9 BinaryTree (com.sun.source.tree.BinaryTree)9 ExpressionStatementTree (com.sun.source.tree.ExpressionStatementTree)8 MethodTree (com.sun.source.tree.MethodTree)8 TreePath (com.sun.source.util.TreePath)8