Search in sources :

Example 21 with JCFieldAccess

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

the class ASTHelpers method sameVariable.

/**
   * Determines whether two expressions refer to the same variable. Note that returning false
   * doesn't necessarily mean the expressions do *not* refer to the same field. We don't attempt
   * to do any complex analysis here, just catch the obvious cases.
   */
public static boolean sameVariable(ExpressionTree expr1, ExpressionTree expr2) {
    // Throw up our hands if we're not comparing identifiers and/or field accesses.
    if ((expr1.getKind() != Kind.IDENTIFIER && expr1.getKind() != Kind.MEMBER_SELECT) || (expr2.getKind() != Kind.IDENTIFIER && expr2.getKind() != Kind.MEMBER_SELECT)) {
        return false;
    }
    Symbol sym1 = getSymbol(expr1);
    Symbol sym2 = getSymbol(expr2);
    if (sym1 == null) {
        throw new IllegalStateException("Couldn't get symbol for " + expr1);
    } else if (sym2 == null) {
        throw new IllegalStateException("Couldn't get symbol for " + expr2);
    }
    if (expr1.getKind() == Kind.IDENTIFIER && expr2.getKind() == Kind.IDENTIFIER) {
        // foo == foo?
        return sym1.equals(sym2);
    } else if (expr1.getKind() == Kind.MEMBER_SELECT && expr2.getKind() == Kind.MEMBER_SELECT) {
        // foo.baz.bar == foo.baz.bar?
        return sym1.equals(sym2) && sameVariable(((JCFieldAccess) expr1).selected, ((JCFieldAccess) expr2).selected);
    } else {
        // this.foo == foo?
        ExpressionTree selected = null;
        if (expr1.getKind() == Kind.IDENTIFIER) {
            selected = ((JCFieldAccess) expr2).selected;
        } else {
            selected = ((JCFieldAccess) expr1).selected;
        }
        // TODO(eaftan): really shouldn't be relying on .toString()
        return selected.toString().equals("this") && sym1.equals(sym2);
    }
}
Also used : JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) Symbol(com.sun.tools.javac.code.Symbol) PackageSymbol(com.sun.tools.javac.code.Symbol.PackageSymbol) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 22 with JCFieldAccess

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

the class Matchers method receiverSameAsArgument.

/**
   * Matches when the receiver of an instance method is the same reference as a particular argument to the method.
   * For example, receiverSameAsArgument(1) would match {@code obj.method("", obj)}
   *
   * @param argNum The number of the argument to compare against (zero-based.
   */
public static Matcher<? super MethodInvocationTree> receiverSameAsArgument(final int argNum) {
    return new Matcher<MethodInvocationTree>() {

        @Override
        public boolean matches(MethodInvocationTree t, VisitorState state) {
            List<? extends ExpressionTree> args = t.getArguments();
            if (args.size() <= argNum) {
                return false;
            }
            ExpressionTree arg = args.get(argNum);
            JCExpression methodSelect = (JCExpression) t.getMethodSelect();
            if (methodSelect instanceof JCFieldAccess) {
                JCFieldAccess fieldAccess = (JCFieldAccess) methodSelect;
                return ASTHelpers.sameVariable(fieldAccess.getExpression(), arg);
            } else if (methodSelect instanceof JCIdent) {
                // A bare method call: "equals(foo)".  Receiver is implicitly "this".
                return "this".equals(arg.toString());
            }
            return false;
        }
    };
}
Also used : JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) InstanceMethodMatcher(com.google.errorprone.matchers.method.MethodMatchers.InstanceMethodMatcher) AnyMethodMatcher(com.google.errorprone.matchers.method.MethodMatchers.AnyMethodMatcher) StaticMethodMatcher(com.google.errorprone.matchers.method.MethodMatchers.StaticMethodMatcher) ConstructorMatcher(com.google.errorprone.matchers.method.MethodMatchers.ConstructorMatcher) VisitorState(com.google.errorprone.VisitorState) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 23 with JCFieldAccess

use of com.sun.tools.javac.tree.JCTree.JCFieldAccess 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 24 with JCFieldAccess

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

the class ProtoFieldNullComparison method getMethodName.

private static String getMethodName(ExpressionTree tree) {
    MethodInvocationTree method = (MethodInvocationTree) tree;
    ExpressionTree expressionTree = method.getMethodSelect();
    JCFieldAccess access = (JCFieldAccess) expressionTree;
    return access.sym.getQualifiedName().toString();
}
Also used : JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 25 with JCFieldAccess

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

the class ProtoFieldPreconditionsCheckNotNull method isGetMethodInvocation.

private static boolean isGetMethodInvocation(ExpressionTree tree, VisitorState state) {
    if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) {
        MethodInvocationTree method = (MethodInvocationTree) tree;
        if (!method.getArguments().isEmpty()) {
            return false;
        }
        if (returnsListMatcher.matches(method, state)) {
            return false;
        }
        ExpressionTree expressionTree = method.getMethodSelect();
        if (expressionTree instanceof JCFieldAccess) {
            JCFieldAccess access = (JCFieldAccess) expressionTree;
            String methodName = access.sym.getQualifiedName().toString();
            return isFieldGetMethod(methodName);
        }
        return true;
    }
    return false;
}
Also used : JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Aggregations

JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)35 JCTree (com.sun.tools.javac.tree.JCTree)13 ExpressionTree (com.sun.source.tree.ExpressionTree)12 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)11 JCIdent (com.sun.tools.javac.tree.JCTree.JCIdent)11 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)8 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)7 Type (com.sun.tools.javac.code.Type)6 ListBuffer (com.sun.tools.javac.util.ListBuffer)6 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)5 JCImport (com.sun.tools.javac.tree.JCTree.JCImport)5 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)5 Name (com.sun.tools.javac.util.Name)5 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)4 Symbol (com.sun.tools.javac.code.Symbol)4 JCPrimitiveTypeTree (com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree)4 JCTypeApply (com.sun.tools.javac.tree.JCTree.JCTypeApply)4 JavacTreeMaker (lombok.javac.JavacTreeMaker)4 Fix (com.google.errorprone.fixes.Fix)3 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)3