Search in sources :

Example 26 with ExpressionTree

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

the class ASTHelpers method getRootAssignable.

/**
   * Find the root assignable expression of a chain of field accesses.  If there is no root
   * (i.e, a bare method call or a static method call), return null.
   *
   * <p>Examples:
   * <pre>
   * {@code
   *    a.trim().intern() ==> a
   *    a.b.trim().intern() ==> a.b
   *    this.intValue.foo() ==> this.intValue
   *    this.foo() ==> this
   *    intern() ==> null
   *    String.format() ==> null
   *    java.lang.String.format() ==> null
   * }
   * </pre>
   */
public static ExpressionTree getRootAssignable(MethodInvocationTree methodInvocationTree) {
    if (!(methodInvocationTree instanceof JCMethodInvocation)) {
        throw new IllegalArgumentException("Expected type to be JCMethodInvocation, but was " + methodInvocationTree.getClass());
    }
    // Check for bare method call, e.g. intern().
    if (((JCMethodInvocation) methodInvocationTree).getMethodSelect() instanceof JCIdent) {
        return null;
    }
    // Unwrap the field accesses until you get to an identifier.
    ExpressionTree expr = methodInvocationTree;
    while (expr instanceof JCMethodInvocation) {
        expr = ((JCMethodInvocation) expr).getMethodSelect();
        if (expr instanceof JCFieldAccess) {
            expr = ((JCFieldAccess) expr).getExpression();
        }
    }
    // We only want assignable identifiers.
    Symbol sym = getSymbol(expr);
    if (sym instanceof VarSymbol) {
        return expr;
    }
    return null;
}
Also used : JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) 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) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol)

Example 27 with ExpressionTree

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

the class AbstractArgumentParameterChecker method findReplacements.

private Description findReplacements(List<? extends ExpressionTree> args, com.sun.tools.javac.util.List<VarSymbol> params, boolean isVarArgs, VisitorState state, Tree tree) {
    if (args.isEmpty()) {
        return Description.NO_MATCH;
    }
    ImmutableSet<PotentialReplacement> potentialReplacements = potentialReplacementsFunction.apply(state.withPath(new TreePath(state.getPath(), args.get(0))));
    SuggestedFix.Builder fix = SuggestedFix.builder();
    // Don't suggest for the varargs parameter.
    // TODO(eaftan): Reconsider this, especially if the argument is of array type or is itself
    // a varargs parameter.
    int maxArg = isVarArgs ? params.size() - 1 : params.size();
    for (int i = 0; i < maxArg; i++) {
        ExpressionTree arg = args.get(i);
        VarSymbol param = params.get(i);
        if (!validKinds.contains(arg.getKind()) || !parameterPredicate.test(param)) {
            continue;
        }
        String extractedArgumentName = extractArgumentName(arg);
        if (extractedArgumentName == null) {
            continue;
        }
        double currSimilarity = similarityMetric.applyAsDouble(extractedArgumentName, param.getSimpleName().toString());
        if (1.0 - currSimilarity < beta) {
            // No way for any replacement to be at least BETA better than the current argument
            continue;
        }
        ReplacementWithSimilarity bestReplacement = potentialReplacements.stream().filter(replacement -> !replacement.sym().equals(ASTHelpers.getSymbol(arg))).filter(replacement -> isSubtypeHandleCompletionFailures(replacement.sym(), param, state)).map(replacement -> ReplacementWithSimilarity.create(replacement, similarityMetric.applyAsDouble(replacement.argumentName(), param.getSimpleName().toString()))).max(Comparator.comparingDouble(ReplacementWithSimilarity::similarity)).orElse(null);
        if ((bestReplacement != null) && (bestReplacement.similarity() - currSimilarity >= beta)) {
            fix.replace(arg, bestReplacement.replacement().replacementString());
        }
    }
    if (fix.isEmpty()) {
        return Description.NO_MATCH;
    } else {
        return describeMatch(tree, fix.build());
    }
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) Function(java.util.function.Function) NewClassTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Kind(com.sun.source.tree.Tree.Kind) NewClassTree(com.sun.source.tree.NewClassTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) Nullable(javax.annotation.Nullable) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) MethodInvocationTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher) TreePath(com.sun.source.util.TreePath) ImmutableSet(com.google.common.collect.ImmutableSet) ExpressionTree(com.sun.source.tree.ExpressionTree) Predicate(java.util.function.Predicate) Symbol(com.sun.tools.javac.code.Symbol) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ToDoubleBiFunction(java.util.function.ToDoubleBiFunction) List(java.util.List) CompletionFailure(com.sun.tools.javac.code.Symbol.CompletionFailure) Description(com.google.errorprone.matchers.Description) AutoValue(com.google.auto.value.AutoValue) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) Comparator(java.util.Comparator) ASTHelpers(com.google.errorprone.util.ASTHelpers) Type(com.sun.tools.javac.code.Type) TreePath(com.sun.source.util.TreePath) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ExpressionTree(com.sun.source.tree.ExpressionTree) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol)

Example 28 with ExpressionTree

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

the class AbstractSuppressWarningsMatcher method getSuggestedFix.

protected final Fix getSuggestedFix(AnnotationTree annotationTree) {
    List<String> values = new ArrayList<>();
    for (ExpressionTree argumentTree : annotationTree.getArguments()) {
        AssignmentTree assignmentTree = (AssignmentTree) argumentTree;
        if (assignmentTree.getVariable().toString().equals("value")) {
            ExpressionTree expressionTree = assignmentTree.getExpression();
            switch(expressionTree.getKind()) {
                case STRING_LITERAL:
                    values.add(((String) ((JCTree.JCLiteral) expressionTree).value));
                    break;
                case NEW_ARRAY:
                    NewArrayTree newArrayTree = (NewArrayTree) expressionTree;
                    for (ExpressionTree elementTree : newArrayTree.getInitializers()) {
                        values.add((String) ((JCTree.JCLiteral) elementTree).value);
                    }
                    break;
                default:
                    throw new AssertionError("Unknown kind: " + expressionTree.getKind());
            }
            processSuppressWarningsValues(values);
        } else {
            throw new AssertionError("SuppressWarnings has an element other than value=");
        }
    }
    if (values.isEmpty()) {
        return SuggestedFix.delete(annotationTree);
    } else if (values.size() == 1) {
        return SuggestedFix.replace(annotationTree, "@SuppressWarnings(\"" + values.get(0) + "\")");
    } else {
        StringBuilder sb = new StringBuilder("@SuppressWarnings({\"" + values.get(0) + "\"");
        for (int i = 1; i < values.size(); i++) {
            sb.append(", ");
            sb.append("\"" + values.get(i) + "\"");
        }
        sb.append("})");
        return SuggestedFix.replace(annotationTree, sb.toString());
    }
}
Also used : NewArrayTree(com.sun.source.tree.NewArrayTree) ArrayList(java.util.ArrayList) ExpressionTree(com.sun.source.tree.ExpressionTree) JCTree(com.sun.tools.javac.tree.JCTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 29 with ExpressionTree

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

the class ArrayHashCode method matchMethodInvocation.

/**
   * Wraps identity hashcode computations in calls to {@link java.util.Arrays#hashCode} if the
   * array is single dimensional or {@link java.util.Arrays#deepHashCode} if the array is
   * multidimensional.
   *
   * <p>If there is only one argument to the hashcode method or the instance hashcode method is
   * used, replaces the whole method invocation.  If there are multiple arguments, wraps any that
   * are of array type with the appropriate {@link java.util.Arrays} hashcode method.
   */
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    SuggestedFix.Builder fix = null;
    Types types = state.getTypes();
    if (jdk7HashCodeMethodMatcher.matches(tree, state)) {
        // java.util.Objects#hashCode takes a single argument, so rewrite the whole method call
        // to use Arrays.hashCode/deepHashCode instead.
        fix = SuggestedFix.builder().replace(tree, rewriteArrayArgument(tree.getArguments().get(0), types));
    } else if (instanceHashCodeMethodMatcher.matches(tree, state)) {
        // Rewrite call to instance hashCode method to use Arrays.hashCode/deepHashCode instead.
        fix = SuggestedFix.builder().replace(tree, rewriteArrayArgument(((JCFieldAccess) tree.getMethodSelect()).getExpression(), types));
    } else if (varargsHashCodeMethodMatcher.matches(tree, state)) {
        // com.google.common.base.Objects#hashCode
        if (tree.getArguments().size() == 1) {
            // If only one argument, type must be either primitive array or multidimensional array.
            // Types like Object[], String[], etc. are not an error because they don't get boxed
            // in this single-argument varargs call.
            ExpressionTree arg = tree.getArguments().get(0);
            Type elemType = types.elemtype(ASTHelpers.getType(arg));
            if (elemType.isPrimitive() || types.isArray(elemType)) {
                fix = SuggestedFix.builder().replace(tree, rewriteArrayArgument(arg, types));
            }
        } else {
            // If more than one argument, wrap each argument in a call to Arrays#hashCode/deepHashCode.
            fix = SuggestedFix.builder();
            for (ExpressionTree arg : tree.getArguments()) {
                if (types.isArray(ASTHelpers.getType(arg))) {
                    fix.replace(arg, rewriteArrayArgument(arg, types));
                }
            }
        }
    }
    if (fix != null) {
        fix.addImport("java.util.Arrays");
        return describeMatch(tree, fix.build());
    }
    return Description.NO_MATCH;
}
Also used : Types(com.sun.tools.javac.code.Types) MatchType(com.google.errorprone.matchers.ChildMultiMatcher.MatchType) Type(com.sun.tools.javac.code.Type) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) ExpressionTree(com.sun.source.tree.ExpressionTree)

Example 30 with ExpressionTree

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

the class BadComparable method matches.

/**
   * Matches if this is a narrowing integral cast between signed types where the expression is a
   * subtract.
   */
private boolean matches(TypeCastTree tree, VisitorState state) {
    Type treeType = ASTHelpers.getType(tree.getType());
    // If the cast isn't narrowing to an int then don't implicate it in the bug pattern.
    if (treeType.getTag() != TypeTag.INT) {
        return false;
    }
    // The expression should be a subtract but remove parentheses.
    ExpressionTree expression = TreeInfo.skipParens((JCExpression) tree.getExpression());
    if (expression.getKind() != Kind.MINUS) {
        return false;
    }
    // Ensure the expression type is wider and signed (ie a long) than the cast type ignoring
    // boxing.
    Type expressionType = getTypeOfSubtract((BinaryTree) expression);
    TypeTag expressionTypeTag = state.getTypes().unboxedTypeOrType(expressionType).getTag();
    return (expressionTypeTag == TypeTag.LONG);
}
Also used : Type(com.sun.tools.javac.code.Type) ExpressionTree(com.sun.source.tree.ExpressionTree) TypeTag(com.sun.tools.javac.code.TypeTag)

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