Search in sources :

Example 36 with MethodTree

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

the class CreatesDuplicateCallHeuristic method findArgumentsForOtherInstances.

/**
 * Find all the other calls to {@code calledMethod} within the method (or class) which enclosed
 * the original call.
 *
 * <p>We are interested in two different cases: 1) where there are other calls to the method we
 * are calling; 2) declarations of the method we are calling (this catches the case when there is
 * a recursive call with the arguments correctly swapped).
 *
 * @param calledMethod is the method call we are analysing for swaps
 * @param currentNode is the tree node the method call occurred at
 * @param state is the current visitor state
 * @return a list containing argument lists for each call found
 */
private static List<List<Parameter>> findArgumentsForOtherInstances(MethodSymbol calledMethod, Tree currentNode, VisitorState state) {
    Tree enclosingNode = ASTHelpers.findEnclosingNode(state.getPath(), MethodTree.class);
    if (enclosingNode == null) {
        enclosingNode = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
    }
    if (enclosingNode == null) {
        return ImmutableList.of();
    }
    ImmutableList.Builder<List<Parameter>> resultBuilder = ImmutableList.builder();
    new TreeScanner<Void, Void>() {

        @Override
        public Void visitMethodInvocation(MethodInvocationTree methodInvocationTree, Void aVoid) {
            addToResult(ASTHelpers.getSymbol(methodInvocationTree), methodInvocationTree);
            return super.visitMethodInvocation(methodInvocationTree, aVoid);
        }

        @Override
        public Void visitNewClass(NewClassTree newClassTree, Void aVoid) {
            addToResult(ASTHelpers.getSymbol(newClassTree), newClassTree);
            return super.visitNewClass(newClassTree, aVoid);
        }

        @Override
        public Void visitMethod(MethodTree methodTree, Void aVoid) {
            MethodSymbol methodSymbol = ASTHelpers.getSymbol(methodTree);
            if (methodSymbol != null) {
                // if the method declared here is the one we are calling then add it
                addToResult(methodSymbol, methodTree);
                // if any supermethod of the one declared here is the one we are calling then add it
                for (MethodSymbol superSymbol : ASTHelpers.findSuperMethods(methodSymbol, state.getTypes())) {
                    addToResult(superSymbol, methodTree);
                }
            }
            return super.visitMethod(methodTree, aVoid);
        }

        private void addToResult(MethodSymbol foundSymbol, Tree tree) {
            if (foundSymbol != null && Objects.equals(calledMethod, foundSymbol) && !currentNode.equals(tree)) {
                resultBuilder.add(createParameterList(tree));
            }
        }

        private ImmutableList<Parameter> createParameterList(Tree tree) {
            if (tree instanceof MethodInvocationTree) {
                return Parameter.createListFromExpressionTrees(((MethodInvocationTree) tree).getArguments());
            }
            if (tree instanceof NewClassTree) {
                return Parameter.createListFromExpressionTrees(((NewClassTree) tree).getArguments());
            }
            if (tree instanceof MethodTree) {
                return Parameter.createListFromVariableTrees(((MethodTree) tree).getParameters());
            }
            return ImmutableList.of();
        }
    }.scan(enclosingNode, null);
    return resultBuilder.build();
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) ImmutableList(com.google.common.collect.ImmutableList) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewClassTree(com.sun.source.tree.NewClassTree) MethodTree(com.sun.source.tree.MethodTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) NewClassTree(com.sun.source.tree.NewClassTree)

Example 37 with MethodTree

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

the class CompatibleWithMisuse method matchAnnotation.

@Override
public Description matchAnnotation(AnnotationTree annoTree, VisitorState state) {
    if (!IS_COMPATIBLE_WITH_ANNOTATION.matches(annoTree, state)) {
        return Description.NO_MATCH;
    }
    // Hunt for type args on the declared method
    // TODO(glorioso): Once annotation is TYPE_USE, make sure that the node is actually a method
    // parameter
    MethodTree methodTree = ASTHelpers.findEnclosingNode(state.getPath(), MethodTree.class);
    MethodSymbol declaredMethod = ASTHelpers.getSymbol(methodTree);
    // This restriction may need to be removed to allow more complex declaration hierarchies.
    for (MethodSymbol methodSymbol : ASTHelpers.findSuperMethods(declaredMethod, state.getTypes())) {
        if (methodSymbol.params().stream().anyMatch(p -> ASTHelpers.hasAnnotation(p, CompatibleWith.class, state))) {
            return describeWithMessage(annoTree, String.format("This method overrides a method in %s that already has @CompatibleWith", methodSymbol.owner.getSimpleName()));
        }
    }
    List<TypeVariableSymbol> potentialTypeVars = new ArrayList<>(declaredMethod.getTypeParameters());
    // Check enclosing types (not superclasses)
    ClassSymbol cs = (ClassSymbol) declaredMethod.owner;
    do {
        potentialTypeVars.addAll(cs.getTypeParameters());
        cs = cs.isInner() ? cs.owner.enclClass() : null;
    } while (cs != null);
    if (potentialTypeVars.isEmpty()) {
        return describeWithMessage(annoTree, "There are no type arguments in scope to match against.");
    }
    Set<String> validNames = potentialTypeVars.stream().map(TypeVariableSymbol::getSimpleName).map(Object::toString).collect(toImmutableSet());
    String constValue = valueArgumentFromCompatibleWithAnnotation(annoTree);
    if (constValue == null || constValue.isEmpty()) {
        return describeWithMessage(annoTree, String.format("The value of @CompatibleWith must not be empty (valid arguments are %s)", printTypeArgs(validNames)));
    }
    return validNames.contains(constValue) ? Description.NO_MATCH : describeWithMessage(annoTree, String.format("%s is not a valid type argument. Valid arguments are: %s", constValue, printTypeArgs(validNames)));
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ArrayList(java.util.ArrayList) TypeVariableSymbol(com.sun.tools.javac.code.Symbol.TypeVariableSymbol) CompatibleWith(com.google.errorprone.annotations.CompatibleWith)

Example 38 with MethodTree

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

the class ForOverrideChecker method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    MethodSymbol method = ASTHelpers.getSymbol(tree);
    if (method == null) {
        return Description.NO_MATCH;
    }
    Type currentClass = getOutermostClass(state);
    if (method.isStatic() || method.isConstructor() || currentClass == null) {
        return Description.NO_MATCH;
    }
    // allow super.foo() calls to @ForOverride methods from overriding methods
    if (isSuperCall(currentClass, tree, state)) {
        MethodTree currentMethod = findDirectMethod(state.getPath());
        // currentMethod might be null if we are in a field initializer
        if (currentMethod != null) {
            // MethodSymbol.overrides doesn't check that names match, so we need to do that first.
            if (currentMethod.getName().equals(method.name)) {
                MethodSymbol currentMethodSymbol = ASTHelpers.getSymbol(currentMethod);
                if (currentMethodSymbol.overrides(method, (TypeSymbol) method.owner, state.getTypes(), /* checkResult= */
                true)) {
                    return Description.NO_MATCH;
                }
            }
        }
    }
    List<MethodSymbol> overriddenMethods = getOverriddenMethods(state, method);
    for (Symbol overriddenMethod : overriddenMethods) {
        Type declaringClass = overriddenMethod.outermostClass().asType();
        if (!declaringClass.equals(currentClass)) {
            String customMessage = MESSAGE_BASE + "must not be invoked directly " + "(except by the declaring class, " + declaringClass + ")";
            return buildDescription(tree).setMessage(customMessage).build();
        }
    }
    return Description.NO_MATCH;
}
Also used : Type(com.sun.tools.javac.code.Type) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) Symbol(com.sun.tools.javac.code.Symbol)

Example 39 with MethodTree

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

the class DoubleBraceInitialization method matchNewClass.

@Override
public Description matchNewClass(NewClassTree tree, VisitorState state) {
    ClassTree body = tree.getClassBody();
    if (body == null) {
        return NO_MATCH;
    }
    ImmutableList<? extends Tree> members = body.getMembers().stream().filter(m -> !(m instanceof MethodTree && ASTHelpers.isGeneratedConstructor((MethodTree) m))).collect(toImmutableList());
    if (members.size() != 1) {
        return NO_MATCH;
    }
    Tree member = Iterables.getOnlyElement(members);
    if (!(member instanceof BlockTree)) {
        return NO_MATCH;
    }
    BlockTree block = (BlockTree) member;
    Optional<CollectionTypes> collectionType = Stream.of(CollectionTypes.values()).filter(type -> type.constructorMatcher.matches(tree, state)).findFirst();
    if (!collectionType.isPresent()) {
        return NO_MATCH;
    }
    Description.Builder description = buildDescription(tree);
    collectionType.get().maybeFix(tree, state, block).ifPresent(description::addFix);
    return description.build();
}
Also used : Iterables(com.google.common.collect.Iterables) MethodTree(com.sun.source.tree.MethodTree) Modifier(javax.lang.model.element.Modifier) MethodMatchers.instanceMethod(com.google.errorprone.matchers.method.MethodMatchers.instanceMethod) VariableTree(com.sun.source.tree.VariableTree) NewClassTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher) TypePredicates.isDescendantOf(com.google.errorprone.predicates.TypePredicates.isDescendantOf) ArrayList(java.util.ArrayList) MethodMatchers.constructor(com.google.errorprone.matchers.method.MethodMatchers.constructor) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Matchers.expressionStatement(com.google.errorprone.matchers.Matchers.expressionStatement) Kind(com.sun.source.tree.Tree.Kind) ImmutableList(com.google.common.collect.ImmutableList) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) BugPattern(com.google.errorprone.BugPattern) Matcher(com.google.errorprone.matchers.Matcher) Fix(com.google.errorprone.fixes.Fix) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) ElementKind(javax.lang.model.element.ElementKind) ExpressionTree(com.sun.source.tree.ExpressionTree) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Collection(java.util.Collection) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Collectors.joining(java.util.stream.Collectors.joining) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) List(java.util.List) Stream(java.util.stream.Stream) Matchers(com.google.errorprone.matchers.Matchers) Description(com.google.errorprone.matchers.Description) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) MethodMatchers(com.google.errorprone.matchers.method.MethodMatchers) Optional(java.util.Optional) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ASTHelpers(com.google.errorprone.util.ASTHelpers) Description(com.google.errorprone.matchers.Description) MethodTree(com.sun.source.tree.MethodTree) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) ExpressionTree(com.sun.source.tree.ExpressionTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) BlockTree(com.sun.source.tree.BlockTree)

Example 40 with MethodTree

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

the class InputStreamSlowMultibyteRead method maybeMatchReadByte.

private Description maybeMatchReadByte(MethodTree readByteMethod, VisitorState state) {
    if (readByteMethod.getBody() != null) {
        // Null-check for native/abstract overrides of read()
        List<? extends StatementTree> statements = readByteMethod.getBody().getStatements();
        if (statements.size() == 1) {
            Tree tree = statements.get(0);
            if (tree.getKind() == Kind.RETURN && ASTHelpers.constValue(((ReturnTree) tree).getExpression()) != null) {
                return Description.NO_MATCH;
            }
        }
    }
    // Streams within JUnit test cases are likely to be OK as well.
    TreePath enclosingPath = ASTHelpers.findPathFromEnclosingNodeToTopLevel(state.getPath(), ClassTree.class);
    while (enclosingPath != null) {
        ClassTree klazz = (ClassTree) enclosingPath.getLeaf();
        if (JUnitMatchers.isTestCaseDescendant.matches(klazz, state) || hasAnnotation(JUnitMatchers.JUNIT4_RUN_WITH_ANNOTATION).matches(klazz, state)) {
            return Description.NO_MATCH;
        }
        enclosingPath = ASTHelpers.findPathFromEnclosingNodeToTopLevel(enclosingPath, ClassTree.class);
    }
    return describeMatch(readByteMethod);
}
Also used : TreePath(com.sun.source.util.TreePath) ClassTree(com.sun.source.tree.ClassTree) ReturnTree(com.sun.source.tree.ReturnTree) MethodTree(com.sun.source.tree.MethodTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) StatementTree(com.sun.source.tree.StatementTree)

Aggregations

MethodTree (com.sun.source.tree.MethodTree)91 Tree (com.sun.source.tree.Tree)46 ClassTree (com.sun.source.tree.ClassTree)45 VariableTree (com.sun.source.tree.VariableTree)39 ExpressionTree (com.sun.source.tree.ExpressionTree)36 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)28 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)22 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)20 TreePath (com.sun.source.util.TreePath)20 IdentifierTree (com.sun.source.tree.IdentifierTree)19 NewClassTree (com.sun.source.tree.NewClassTree)19 ReturnTree (com.sun.source.tree.ReturnTree)18 ExecutableElement (javax.lang.model.element.ExecutableElement)17 Symbol (com.sun.tools.javac.code.Symbol)16 ArrayList (java.util.ArrayList)15 AssignmentTree (com.sun.source.tree.AssignmentTree)14 BlockTree (com.sun.source.tree.BlockTree)14 CompilationUnitTree (com.sun.source.tree.CompilationUnitTree)14 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)14 MemberSelectTree (com.sun.source.tree.MemberSelectTree)14