Search in sources :

Example 31 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project error-prone by google.

the class AbstractTestExceptionChecker method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    if (tree.getBody() == null) {
        return NO_MATCH;
    }
    SuggestedFix.Builder baseFixBuilder = SuggestedFix.builder();
    JCExpression expectedException = deleteExpectedException(baseFixBuilder, ((JCMethodDecl) tree).getModifiers().getAnnotations(), state);
    SuggestedFix baseFix = baseFixBuilder.build();
    if (expectedException == null) {
        return NO_MATCH;
    }
    return handleStatements(tree, state, expectedException, baseFix);
}
Also used : JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) SuggestedFix(com.google.errorprone.fixes.SuggestedFix)

Example 32 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project error-prone by google.

the class SelfAssignment method describeForAssignment.

/**
   * We expect that the lhs is a field and the rhs is an identifier, specifically
   * a parameter to the method.  We base our suggested fixes on this expectation.
   *
   * Case 1: If lhs is a field and rhs is an identifier, find a method parameter
   * of the same type and similar name and suggest it as the rhs.  (Guess that they
   * have misspelled the identifier.)
   *
   * Case 2: If lhs is a field and rhs is not an identifier, find a method parameter
   * of the same type and similar name and suggest it as the rhs.
   *
   * Case 3: If lhs is not a field and rhs is an identifier, find a class field
   * of the same type and similar name and suggest it as the lhs.
   *
   * Case 4: Otherwise suggest deleting the assignment.
   */
public Description describeForAssignment(AssignmentTree assignmentTree, VisitorState state) {
    // the statement that is the parent of the self-assignment expression
    Tree parent = state.getPath().getParentPath().getLeaf();
    // default fix is to delete assignment
    Fix fix = SuggestedFix.delete(parent);
    ExpressionTree lhs = assignmentTree.getVariable();
    ExpressionTree rhs = assignmentTree.getExpression();
    // if this is a method invocation, they must be calling checkNotNull()
    if (assignmentTree.getExpression().getKind() == METHOD_INVOCATION) {
        // change the default fix to be "checkNotNull(x)" instead of "x = checkNotNull(x)"
        fix = SuggestedFix.replace(assignmentTree, rhs.toString());
        // new rhs is first argument to checkNotNull()
        rhs = stripCheckNotNull(rhs, state);
    }
    if (lhs.getKind() == MEMBER_SELECT) {
        // rhs should be either identifier or field access
        assert (rhs.getKind() == IDENTIFIER || rhs.getKind() == MEMBER_SELECT);
        // get current name of rhs
        String rhsName = null;
        if (rhs.getKind() == IDENTIFIER) {
            rhsName = ((JCIdent) rhs).name.toString();
        } else if (rhs.getKind() == MEMBER_SELECT) {
            rhsName = ((JCFieldAccess) rhs).name.toString();
        }
        // find method parameters of the same type
        Type type = ((JCFieldAccess) lhs).type;
        TreePath path = state.getPath();
        while (path != null && path.getLeaf().getKind() != METHOD) {
            path = path.getParentPath();
        }
        JCMethodDecl method = (JCMethodDecl) path.getLeaf();
        int minEditDistance = Integer.MAX_VALUE;
        String replacement = null;
        for (JCVariableDecl var : method.params) {
            if (var.type == type) {
                int editDistance = EditDistance.getEditDistance(rhsName, var.name.toString());
                if (editDistance < minEditDistance) {
                    // pick one with minimum edit distance
                    minEditDistance = editDistance;
                    replacement = var.name.toString();
                }
            }
        }
        if (replacement != null) {
            // suggest replacing rhs with the parameter
            fix = SuggestedFix.replace(rhs, replacement);
        }
    } else if (rhs.getKind() == IDENTIFIER) {
        // lhs should be identifier
        assert (lhs.getKind() == IDENTIFIER);
        // get current name of lhs
        String lhsName = ((JCIdent) rhs).name.toString();
        // find class instance fields of the same type
        Type type = ((JCIdent) lhs).type;
        TreePath path = state.getPath();
        while (path != null && !(path.getLeaf() instanceof JCClassDecl)) {
            path = path.getParentPath();
        }
        if (path == null) {
            throw new IllegalStateException("Expected to find an enclosing class declaration");
        }
        JCClassDecl klass = (JCClassDecl) path.getLeaf();
        int minEditDistance = Integer.MAX_VALUE;
        String replacement = null;
        for (JCTree member : klass.getMembers()) {
            if (member.getKind() == VARIABLE) {
                JCVariableDecl var = (JCVariableDecl) member;
                if (!Flags.isStatic(var.sym) && var.type == type) {
                    int editDistance = EditDistance.getEditDistance(lhsName, var.name.toString());
                    if (editDistance < minEditDistance) {
                        // pick one with minimum edit distance
                        minEditDistance = editDistance;
                        replacement = var.name.toString();
                    }
                }
            }
        }
        if (replacement != null) {
            // suggest replacing lhs with the field
            fix = SuggestedFix.replace(lhs, "this." + replacement);
        }
    }
    return describeMatch(assignmentTree, fix);
}
Also used : JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) JCTree(com.sun.tools.javac.tree.JCTree) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) Type(com.sun.tools.javac.code.Type) Fix(com.google.errorprone.fixes.Fix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) TreePath(com.sun.source.util.TreePath) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) JCTree(com.sun.tools.javac.tree.JCTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 33 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project error-prone by google.

the class UseBinds method convertMethodToBinds.

private SuggestedFix.Builder convertMethodToBinds(MethodTree method, VisitorState state) {
    SuggestedFix.Builder fix = SuggestedFix.builder();
    JCModifiers modifiers = ((JCMethodDecl) method).getModifiers();
    ImmutableList.Builder<String> modifierStringsBuilder = new ImmutableList.Builder<String>().add("@Binds");
    for (JCAnnotation annotation : modifiers.annotations) {
        Name annotationQualifiedName = getSymbol(annotation).getQualifiedName();
        if (annotationQualifiedName.contentEquals(PROVIDES_CLASS_NAME) || annotationQualifiedName.contentEquals(PRODUCES_CLASS_NAME)) {
            List<JCExpression> arguments = annotation.getArguments();
            if (!arguments.isEmpty()) {
                JCExpression argument = Iterables.getOnlyElement(arguments);
                checkState(argument.getKind().equals(ASSIGNMENT));
                JCAssign assignment = (JCAssign) argument;
                checkState(getSymbol(assignment.getVariable()).getSimpleName().contentEquals("type"));
                String typeName = getSymbol(assignment.getExpression()).getSimpleName().toString();
                switch(typeName) {
                    case "SET":
                        modifierStringsBuilder.add("@IntoSet");
                        fix.addImport(INTO_SET_CLASS_NAME);
                        break;
                    case "SET_VALUES":
                        modifierStringsBuilder.add("@ElementsIntoSet");
                        fix.addImport(ELEMENTS_INTO_SET_CLASS_NAME);
                        break;
                    case "MAP":
                        modifierStringsBuilder.add("@IntoMap");
                        fix.addImport(INTO_MAP_CLASS_NAME);
                        break;
                    default:
                        throw new AssertionError("Unknown type name: " + typeName);
                }
            }
        } else {
            modifierStringsBuilder.add(state.getSourceForNode(annotation));
        }
    }
    EnumSet<Flag> methodFlags = Flags.asFlagSet(modifiers.flags);
    methodFlags.remove(Flags.Flag.STATIC);
    methodFlags.remove(Flags.Flag.FINAL);
    methodFlags.add(Flags.Flag.ABSTRACT);
    for (Flag flag : methodFlags) {
        modifierStringsBuilder.add(flag.toString());
    }
    fix.replace(modifiers, Joiner.on(' ').join(modifierStringsBuilder.build()));
    fix.replace(method.getBody(), ";");
    return fix;
}
Also used : JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCAssign(com.sun.tools.javac.tree.JCTree.JCAssign) ImmutableList(com.google.common.collect.ImmutableList) Flag(com.sun.tools.javac.code.Flags.Flag) Name(com.sun.tools.javac.util.Name) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) JCModifiers(com.sun.tools.javac.tree.JCTree.JCModifiers) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation)

Example 34 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project error-prone by google.

the class ReturnMissingNullable method matchReturn.

@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
    ExpressionTree returnExpression = tree.getExpression();
    if (returnExpression == null) {
        return Description.NO_MATCH;
    }
    // TODO(kmb): bail on more non-null expressions, such as "this", arithmethic, logical, and &&/||
    if (ASTHelpers.constValue(returnExpression) != null) {
        // This should include literals such as "true" or a string
        return Description.NO_MATCH;
    }
    JCMethodDecl method = findSurroundingMethod(state.getPath());
    if (method == null || isIgnoredReturnType(method, state)) {
        return Description.NO_MATCH;
    }
    if (TrustingNullnessAnalysis.hasNullableAnnotation(method.sym)) {
        return Description.NO_MATCH;
    }
    // Don't need dataflow to tell us that null is nullable
    if (returnExpression.getKind() == ExpressionTree.Kind.NULL_LITERAL) {
        return makeFix(method, tree, "Returning null literal");
    }
    // OK let's see what dataflow says
    Nullness nullness = TrustingNullnessAnalysis.instance(state.context).getNullness(new TreePath(state.getPath(), returnExpression), state.context);
    switch(nullness) {
        case BOTTOM:
        case NONNULL:
            return Description.NO_MATCH;
        case NULL:
            return makeFix(method, tree, "Definitely returning null");
        case NULLABLE:
            return makeFix(method, tree, "May return null");
        default:
            throw new AssertionError("Impossible: " + nullness);
    }
}
Also used : JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) TreePath(com.sun.source.util.TreePath) ExpressionTree(com.sun.source.tree.ExpressionTree) Nullness(com.google.errorprone.dataflow.nullnesspropagation.Nullness)

Example 35 with JCMethodDecl

use of com.sun.tools.javac.tree.JCTree.JCMethodDecl in project error-prone by google.

the class EmptySetMultibindingContributions method fixByModifyingMethod.

private Description fixByModifyingMethod(VisitorState state, JCClassDecl enclosingClass, MethodTree method) {
    JCModifiers methodModifiers = ((JCMethodDecl) method).getModifiers();
    String replacementModifiersString = createReplacementMethodModifiers(state, methodModifiers);
    JCModifiers enclosingClassModifiers = enclosingClass.getModifiers();
    String enclosingClassReplacementModifiersString = createReplacementClassModifiers(state, enclosingClassModifiers);
    SuggestedFix.Builder fixBuilder = SuggestedFix.builder().addImport("dagger.multibindings.Multibinds").replace(methodModifiers, replacementModifiersString).replace(method.getBody(), ";");
    fixBuilder = (enclosingClassModifiers.pos == -1) ? fixBuilder.prefixWith(enclosingClass, enclosingClassReplacementModifiersString) : fixBuilder.replace(enclosingClassModifiers, enclosingClassReplacementModifiersString);
    return describeMatch(method, fixBuilder.build());
}
Also used : JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) JCModifiers(com.sun.tools.javac.tree.JCTree.JCModifiers)

Aggregations

JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)45 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)31 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)20 Name (com.sun.tools.javac.util.Name)17 JCBlock (com.sun.tools.javac.tree.JCTree.JCBlock)16 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)16 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)15 ListBuffer (com.sun.tools.javac.util.ListBuffer)14 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)13 JCModifiers (com.sun.tools.javac.tree.JCTree.JCModifiers)13 JavacNode (lombok.javac.JavacNode)13 JCTree (com.sun.tools.javac.tree.JCTree)12 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)5 Type (com.sun.tools.javac.code.Type)5 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)5 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)5 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)5 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)4 JavacTreeMaker (lombok.javac.JavacTreeMaker)4 JCExpressionStatement (com.sun.tools.javac.tree.JCTree.JCExpressionStatement)3