Search in sources :

Example 41 with ExpressionTree

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

the class AbstractExpectedExceptionChecker method buildBaseFix.

protected BaseFix buildBaseFix(VisitorState state, List<Tree> expectations) {
    String exceptionClass = "Throwable";
    // additional assertions to perform on the captured exception (if any)
    List<String> newAsserts = new ArrayList<>();
    Builder fix = SuggestedFix.builder();
    for (Tree expectation : expectations) {
        MethodInvocationTree invocation = (MethodInvocationTree) ((ExpressionStatementTree) expectation).getExpression();
        MethodSymbol symbol = ASTHelpers.getSymbol(invocation);
        Symtab symtab = state.getSymtab();
        List<? extends ExpressionTree> args = invocation.getArguments();
        switch(symbol.getSimpleName().toString()) {
            case "expect":
                if (isSubtype(getOnlyElement(symbol.getParameters()).asType(), symtab.classType, state)) {
                    // expect(Class<?>)
                    exceptionClass = state.getSourceForNode(getReceiver(getOnlyElement(args)));
                } else {
                    // expect(Matcher)
                    fix.addStaticImport("org.hamcrest.MatcherAssert.assertThat");
                    newAsserts.add(String.format("assertThat(thrown, %s);", state.getSourceForNode(getOnlyElement(args))));
                }
                break;
            case "expectCause":
                ExpressionTree matcher = getOnlyElement(invocation.getArguments());
                if (IS_A.matches(matcher, state)) {
                    fix.addStaticImport("com.google.common.truth.Truth.assertThat");
                    newAsserts.add(String.format("assertThat(thrown).hasCauseThat().isInstanceOf(%s);", state.getSourceForNode(getOnlyElement(((MethodInvocationTree) matcher).getArguments()))));
                } else {
                    fix.addStaticImport("org.hamcrest.MatcherAssert.assertThat");
                    newAsserts.add(String.format("assertThat(thrown.getCause(), %s);", state.getSourceForNode(getOnlyElement(args))));
                }
                break;
            case "expectMessage":
                if (isSubtype(getOnlyElement(symbol.getParameters()).asType(), symtab.stringType, state)) {
                    // expectedMessage(String)
                    fix.addStaticImport("com.google.common.truth.Truth.assertThat");
                    newAsserts.add(String.format("assertThat(thrown).hasMessageThat().contains(%s);", state.getSourceForNode(getOnlyElement(args))));
                } else {
                    // expectedMessage(Matcher)
                    fix.addStaticImport("org.hamcrest.MatcherAssert.assertThat");
                    newAsserts.add(String.format("assertThat(thrown.getMessage(), %s);", state.getSourceForNode(getOnlyElement(args))));
                }
                break;
            default:
                throw new AssertionError("unknown expect method: " + symbol.getSimpleName());
        }
    }
    // remove all interactions with the ExpectedException rule
    fix.replace(((JCTree) expectations.get(0)).getStartPosition(), state.getEndPosition(getLast(expectations)), "");
    return new BaseFix(fix.build(), exceptionClass, newAsserts);
}
Also used : Symtab(com.sun.tools.javac.code.Symtab) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Builder(com.google.errorprone.fixes.SuggestedFix.Builder) ArrayList(java.util.ArrayList) MethodTree(com.sun.source.tree.MethodTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) JCTree(com.sun.tools.javac.tree.JCTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) StatementTree(com.sun.source.tree.StatementTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 42 with ExpressionTree

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

the class AbstractReferenceEquality method addFixes.

protected void addFixes(Description.Builder builder, BinaryTree tree, VisitorState state) {
    ExpressionTree lhs = tree.getLeftOperand();
    ExpressionTree rhs = tree.getRightOperand();
    Optional<Fix> fixToReplaceOrStatement = inOrStatementWithEqualsCheck(state, tree);
    if (fixToReplaceOrStatement.isPresent()) {
        builder.addFix(fixToReplaceOrStatement.get());
        return;
    }
    // Swap the order (e.g. rhs.equals(lhs) if the rhs is a non-null constant, and the lhs is not
    if (ASTHelpers.constValue(lhs) == null && ASTHelpers.constValue(rhs) != null) {
        ExpressionTree tmp = lhs;
        lhs = rhs;
        rhs = tmp;
    }
    String prefix = tree.getKind() == Kind.NOT_EQUAL_TO ? "!" : "";
    String lhsSource = state.getSourceForNode(lhs);
    String rhsSource = state.getSourceForNode(rhs);
    Nullness nullness = getNullness(lhs, state);
    // If the lhs is possibly-null, provide both options.
    if (nullness != NONNULL) {
        builder.addFix(SuggestedFix.builder().replace(tree, String.format("%sObjects.equals(%s, %s)", prefix, lhsSource, rhsSource)).addImport("java.util.Objects").build());
    }
    if (nullness != NULL) {
        builder.addFix(SuggestedFix.replace(tree, String.format("%s%s.equals(%s)", prefix, lhs instanceof BinaryTree ? String.format("(%s)", lhsSource) : lhsSource, rhsSource)));
    }
}
Also used : SuggestedFix(com.google.errorprone.fixes.SuggestedFix) Fix(com.google.errorprone.fixes.Fix) BinaryTree(com.sun.source.tree.BinaryTree) ExpressionTree(com.sun.source.tree.ExpressionTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Example 43 with ExpressionTree

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

the class AbstractReferenceEquality method inOrStatementWithEqualsCheck.

private static Optional<Fix> inOrStatementWithEqualsCheck(VisitorState state, BinaryTree tree) {
    // Only attempt to handle a == b || a.equals(b);
    if (tree.getKind() == Kind.NOT_EQUAL_TO) {
        return Optional.empty();
    }
    ExpressionTree lhs = tree.getLeftOperand();
    ExpressionTree rhs = tree.getRightOperand();
    Tree parent = state.getPath().getParentPath().getLeaf();
    if (parent.getKind() != Kind.CONDITIONAL_OR) {
        return Optional.empty();
    }
    BinaryTree p = (BinaryTree) parent;
    if (p.getLeftOperand() != tree) {
        // a == b is on the RHS, ignore this construction
        return Optional.empty();
    }
    // If the other half of this or statement is foo.equals(bar) or Objects.equals(foo, bar)
    // replace the or statement with the other half as already written.
    ExpressionTree otherExpression = skipParens(p.getRightOperand());
    if (!(otherExpression instanceof MethodInvocationTree)) {
        return Optional.empty();
    }
    MethodInvocationTree other = (MethodInvocationTree) otherExpression;
    // a == b || Objects.equals(a, b) => Objects.equals(a, b)
    if (EQUALS_STATIC_METHODS.matches(otherExpression, state)) {
        List<? extends ExpressionTree> arguments = other.getArguments();
        if (treesMatch(arguments.get(0), arguments.get(1), lhs, rhs)) {
            return Optional.of(SuggestedFix.replace(parent, state.getSourceForNode(otherExpression)));
        }
    }
    // a == b || a.equals(b) => a.equals(b)
    if (OBJECT_INSTANCE_EQUALS.matches(otherExpression, state)) {
        if (treesMatch(ASTHelpers.getReceiver(other), other.getArguments().get(0), lhs, rhs)) {
            return Optional.of(SuggestedFix.replace(parent, state.getSourceForNode(otherExpression)));
        }
    }
    return Optional.empty();
}
Also used : MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) BinaryTree(com.sun.source.tree.BinaryTree) ExpressionTree(com.sun.source.tree.ExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) BinaryTree(com.sun.source.tree.BinaryTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Tree(com.sun.source.tree.Tree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree)

Example 44 with ExpressionTree

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

the class AbstractReturnValueIgnored method describe.

/**
   * Fixes the error by assigning the result of the call to the receiver reference, or deleting the
   * method call.
   */
public Description describe(MethodInvocationTree methodInvocationTree, VisitorState state) {
    // Find the root of the field access chain, i.e. a.intern().trim() ==> a.
    ExpressionTree identifierExpr = ASTHelpers.getRootAssignable(methodInvocationTree);
    String identifierStr = null;
    Type identifierType = null;
    if (identifierExpr != null) {
        identifierStr = identifierExpr.toString();
        if (identifierExpr instanceof JCIdent) {
            identifierType = ((JCIdent) identifierExpr).sym.type;
        } else if (identifierExpr instanceof JCFieldAccess) {
            identifierType = ((JCFieldAccess) identifierExpr).sym.type;
        } else {
            throw new IllegalStateException("Expected a JCIdent or a JCFieldAccess");
        }
    }
    Type returnType = ASTHelpers.getReturnType(((JCMethodInvocation) methodInvocationTree).getMethodSelect());
    Fix fix;
    if (identifierStr != null && !"this".equals(identifierStr) && returnType != null && state.getTypes().isAssignable(returnType, identifierType)) {
        // Fix by assigning the assigning the result of the call to the root receiver reference.
        fix = SuggestedFix.prefixWith(methodInvocationTree, identifierStr + " = ");
    } else {
        // Unclear what the programmer intended.  Delete since we don't know what else to do.
        Tree parent = state.getPath().getParentPath().getLeaf();
        fix = SuggestedFix.delete(parent);
    }
    return describeMatch(methodInvocationTree, fix);
}
Also used : Type(com.sun.tools.javac.code.Type) JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) Fix(com.google.errorprone.fixes.Fix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) ExpressionTree(com.sun.source.tree.ExpressionTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) StatementTree(com.sun.source.tree.StatementTree)

Example 45 with ExpressionTree

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

the class AbstractTestExceptionChecker method buildFix.

// TODO(cushon): extracting one statement into a lambda may not compile if the statement has
// side effects (e.g. it references a variable in the method that isn't effectively final).
// If this is a problem, consider trying to detect and avoid that case.
protected static SuggestedFix buildFix(VisitorState state, SuggestedFix.Builder fix, JCExpression expectedException, List<? extends StatementTree> statements) {
    fix.addStaticImport("org.junit.Assert.assertThrows");
    StringBuilder prefix = new StringBuilder();
    prefix.append(String.format("assertThrows(%s, () -> ", state.getSourceForNode(expectedException)));
    if (statements.size() == 1 && getOnlyElement(statements) instanceof ExpressionStatementTree) {
        ExpressionTree expression = ((ExpressionStatementTree) getOnlyElement(statements)).getExpression();
        fix.prefixWith(expression, prefix.toString());
        fix.postfixWith(expression, ")");
    } else {
        prefix.append(" {");
        fix.prefixWith(statements.iterator().next(), prefix.toString());
        fix.postfixWith(getLast(statements), "});");
    }
    return fix.build();
}
Also used : ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

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