Search in sources :

Example 46 with ExpressionTree

use of com.sun.source.tree.ExpressionTree 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 47 with ExpressionTree

use of com.sun.source.tree.ExpressionTree 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 48 with ExpressionTree

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

the class IsLoggableTagLength method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    if (!IS_LOGGABLE_CALL.matches(tree, state)) {
        return NO_MATCH;
    }
    ExpressionTree tagArg = tree.getArguments().get(0);
    // Check for constant value.
    String tagConstantValue = ASTHelpers.constValue(tagArg, String.class);
    if (tagConstantValue != null) {
        return isValidTag(tagConstantValue) ? NO_MATCH : describeMatch(tagArg);
    }
    // Check for class literal simple name (e.g. MyClass.class.getSimpleName().
    ExpressionTree tagExpr = tagArg;
    // If the tag argument is a final field, retrieve the initializer.
    if (kindIs(IDENTIFIER).matches(tagArg, state)) {
        VariableTree declaredField = findEnclosingIdentifier((IdentifierTree) tagArg, state);
        if (declaredField == null || !hasModifier(FINAL).matches(declaredField, state)) {
            return NO_MATCH;
        }
        tagExpr = declaredField.getInitializer();
    }
    if (GET_SIMPLE_NAME_CALL.matches(tagExpr, state) && RECEIVER_IS_CLASS_LITERAL.matches((MethodInvocationTree) tagExpr, state)) {
        String tagName = getSymbol(getReceiver(getReceiver(tagExpr))).getSimpleName().toString();
        return isValidTag(tagName) ? NO_MATCH : describeMatch(tagArg);
    }
    return NO_MATCH;
}
Also used : MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) VariableTree(com.sun.source.tree.VariableTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 49 with ExpressionTree

use of com.sun.source.tree.ExpressionTree 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 50 with ExpressionTree

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

the class IncompatibleArgumentType method reportAnyViolations.

private void reportAnyViolations(List<? extends ExpressionTree> arguments, List<RequiredType> requiredTypesAtCallSite, VisitorState state) {
    Types types = state.getTypes();
    for (int i = 0; i < requiredTypesAtCallSite.size(); i++) {
        RequiredType requiredType = requiredTypesAtCallSite.get(i);
        if (requiredType == null) {
            continue;
        }
        ExpressionTree argument = arguments.get(i);
        Type argType = ASTHelpers.getType(argument);
        if (requiredType.type() != null && !types.isCastable(argType, types.erasure(ASTHelpers.getUpperBound(requiredType.type(), types)))) {
            // Report a violation for this type
            state.reportMatch(describeViolation(argument, argType, requiredType.type(), types));
        }
    }
}
Also used : Types(com.sun.tools.javac.code.Types) Type(com.sun.tools.javac.code.Type) 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