Search in sources :

Example 1 with CONSTRUCTOR

use of javax.lang.model.element.ElementKind.CONSTRUCTOR in project error-prone by google.

the class UnusedMethod method matchCompilationUnit.

@Override
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
    // Map of symbols to method declarations. Initially this is a map of all of the methods. As we
    // go we remove those variables which are used.
    Map<Symbol, TreePath> unusedMethods = new HashMap<>();
    // Use a TreeScanner to find all local variables and fields.
    if (hasNativeMethods(tree)) {
        return Description.NO_MATCH;
    }
    AtomicBoolean ignoreUnusedMethods = new AtomicBoolean(false);
    class MethodFinder extends SuppressibleTreePathScanner<Void, Void> {

        MethodFinder(VisitorState state) {
            super(state);
        }

        @Override
        public Void visitClass(ClassTree tree, Void unused) {
            if (exemptedBySuperType(getType(tree), state)) {
                return null;
            }
            return super.visitClass(tree, null);
        }

        private boolean exemptedBySuperType(Type type, VisitorState state) {
            return EXEMPTING_SUPER_TYPES.stream().anyMatch(t -> isSubtype(type, typeFromString(t).get(state), state));
        }

        @Override
        public Void visitMethod(MethodTree tree, Void unused) {
            if (hasJUnitParamsParametersForMethodAnnotation(tree.getModifiers().getAnnotations())) {
                // Since this method uses @Parameters, there will be another method that appears to
                // be unused. Don't warn about unusedMethods at all in this case.
                ignoreUnusedMethods.set(true);
            }
            if (isMethodSymbolEligibleForChecking(tree)) {
                unusedMethods.put(getSymbol(tree), getCurrentPath());
            }
            return super.visitMethod(tree, unused);
        }

        private boolean hasJUnitParamsParametersForMethodAnnotation(Collection<? extends AnnotationTree> annotations) {
            for (AnnotationTree tree : annotations) {
                JCAnnotation annotation = (JCAnnotation) tree;
                if (annotation.getAnnotationType().type != null && annotation.getAnnotationType().type.toString().equals(JUNIT_PARAMS_ANNOTATION_TYPE)) {
                    if (annotation.getArguments().isEmpty()) {
                        // @Parameters, which uses implicit provider methods
                        return true;
                    }
                    for (JCExpression arg : annotation.getArguments()) {
                        if (arg.getKind() != Kind.ASSIGNMENT) {
                            // Implicit value annotation, e.g. @Parameters({"1"}); no exemption required.
                            return false;
                        }
                        JCExpression var = ((JCAssign) arg).getVariable();
                        if (var.getKind() == Kind.IDENTIFIER) {
                            // @Parameters(source = ...) or @Parameters(method = ...)
                            if (!((IdentifierTree) var).getName().contentEquals(JUNIT_PARAMS_VALUE)) {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        private boolean isMethodSymbolEligibleForChecking(MethodTree tree) {
            if (exemptedByName(tree.getName())) {
                return false;
            }
            // Assume the method is called if annotated with a called-reflectively annotation.
            if (exemptedByAnnotation(tree.getModifiers().getAnnotations())) {
                return false;
            }
            if (shouldKeep(tree)) {
                return false;
            }
            MethodSymbol methodSymbol = getSymbol(tree);
            if (isExemptedConstructor(methodSymbol, state) || isGeneratedConstructor(tree) || SERIALIZATION_METHODS.matches(tree, state)) {
                return false;
            }
            // Ignore this method if the last parameter is a GWT JavaScriptObject.
            if (!tree.getParameters().isEmpty()) {
                Type lastParamType = getType(getLast(tree.getParameters()));
                if (lastParamType != null && lastParamType.toString().equals(GWT_JAVASCRIPT_OBJECT)) {
                    return false;
                }
            }
            return canBeRemoved(methodSymbol, state);
        }

        private boolean isExemptedConstructor(MethodSymbol methodSymbol, VisitorState state) {
            if (!methodSymbol.getKind().equals(CONSTRUCTOR)) {
                return false;
            }
            // instantiating the class at all (e.g. in utility classes).
            if (methodSymbol.params().isEmpty()) {
                return true;
            }
            return false;
        }
    }
    new MethodFinder(state).scan(state.getPath(), null);
    class FilterUsedMethods extends TreePathScanner<Void, Void> {

        @Override
        public Void visitMemberSelect(MemberSelectTree memberSelectTree, Void unused) {
            Symbol symbol = getSymbol(memberSelectTree);
            unusedMethods.remove(symbol);
            return super.visitMemberSelect(memberSelectTree, null);
        }

        @Override
        public Void visitMemberReference(MemberReferenceTree tree, Void unused) {
            super.visitMemberReference(tree, null);
            MethodSymbol symbol = getSymbol(tree);
            unusedMethods.remove(symbol);
            symbol.getParameters().forEach(unusedMethods::remove);
            return null;
        }

        @Override
        public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {
            handle(getSymbol(tree));
            return super.visitMethodInvocation(tree, null);
        }

        @Override
        public Void visitNewClass(NewClassTree tree, Void unused) {
            handle(getSymbol(tree));
            return super.visitNewClass(tree, null);
        }

        @Override
        public Void visitAssignment(AssignmentTree tree, Void unused) {
            handle(getSymbol(tree.getVariable()));
            return super.visitAssignment(tree, unused);
        }

        private void handle(Symbol symbol) {
            if (symbol instanceof MethodSymbol) {
                unusedMethods.remove(symbol);
            }
        }

        @Override
        public Void visitMethod(MethodTree tree, Void unused) {
            handleMethodSource(tree);
            return super.visitMethod(tree, null);
        }

        /**
         * If a method is annotated with @MethodSource, the annotation value refers to another method
         * that is used reflectively to supply test parameters, so that method should not be
         * considered unused.
         */
        private void handleMethodSource(MethodTree tree) {
            MethodSymbol sym = getSymbol(tree);
            Name name = ORG_JUNIT_JUPITER_PARAMS_PROVIDER_METHODSOURCE.get(state);
            sym.getRawAttributes().stream().filter(a -> a.type.tsym.getQualifiedName().equals(name)).findAny().flatMap(a -> getAnnotationValue(a, "value")).map(y -> asStrings(y).map(state::getName).map(Name::toString).collect(toImmutableSet())).ifPresent(referencedNames -> unusedMethods.entrySet().removeIf(e -> {
                Symbol unusedSym = e.getKey();
                String simpleName = unusedSym.getSimpleName().toString();
                return referencedNames.contains(simpleName) || referencedNames.contains(unusedSym.owner.getQualifiedName() + "#" + simpleName);
            }));
        }
    }
    new FilterUsedMethods().scan(state.getPath(), null);
    if (ignoreUnusedMethods.get()) {
        return Description.NO_MATCH;
    }
    fixNonConstructors(unusedMethods.values().stream().filter(t -> !getSymbol(t.getLeaf()).isConstructor()).collect(toImmutableList()), state);
    // Group unused constructors by the owning class to generate fixes, so that if we remove the
    // last constructor, we add a private one.
    ImmutableListMultimap<Symbol, TreePath> unusedConstructors = unusedMethods.values().stream().filter(t -> getSymbol(t.getLeaf()).isConstructor()).collect(toImmutableListMultimap(t -> getSymbol(t.getLeaf()).owner, t -> t));
    fixConstructors(unusedConstructors, state);
    return Description.NO_MATCH;
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) Modifier(javax.lang.model.element.Modifier) SuggestedFixes.replaceIncludingComments(com.google.errorprone.fixes.SuggestedFixes.replaceIncludingComments) MoreAnnotations.asStrings(com.google.errorprone.util.MoreAnnotations.asStrings) ASTHelpers.isGeneratedConstructor(com.google.errorprone.util.ASTHelpers.isGeneratedConstructor) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ImmutableListMultimap.toImmutableListMultimap(com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap) ASTHelpers.shouldKeep(com.google.errorprone.util.ASTHelpers.shouldKeep) AssignmentTree(com.sun.source.tree.AssignmentTree) FINAL(javax.lang.model.element.Modifier.FINAL) IdentifierTree(com.sun.source.tree.IdentifierTree) Map(java.util.Map) Supplier(com.google.errorprone.suppliers.Supplier) Suppliers.typeFromString(com.google.errorprone.suppliers.Suppliers.typeFromString) MoreAnnotations.getAnnotationValue(com.google.errorprone.util.MoreAnnotations.getAnnotationValue) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) TreePath(com.sun.source.util.TreePath) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Collection(java.util.Collection) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) Iterables.getLast(com.google.common.collect.Iterables.getLast) MemberSelectTree(com.sun.source.tree.MemberSelectTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) String.format(java.lang.String.format) TreeScanner(com.sun.source.util.TreeScanner) List(java.util.List) SuggestedFix.emptyFix(com.google.errorprone.fixes.SuggestedFix.emptyFix) CompilationUnitTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher) Description(com.google.errorprone.matchers.Description) Multimaps.asMap(com.google.common.collect.Multimaps.asMap) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) ASTHelpers.scope(com.google.errorprone.util.ASTHelpers.scope) Type(com.sun.tools.javac.code.Type) SERIALIZATION_METHODS(com.google.errorprone.matchers.Matchers.SERIALIZATION_METHODS) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) Iterables.size(com.google.common.collect.Iterables.size) VisitorState(com.google.errorprone.VisitorState) Kind(com.sun.source.tree.Tree.Kind) NewClassTree(com.sun.source.tree.NewClassTree) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) BugPattern(com.google.errorprone.BugPattern) JCAssign(com.sun.tools.javac.tree.JCTree.JCAssign) TreePathScanner(com.sun.source.util.TreePathScanner) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) Name(javax.lang.model.element.Name) Ascii(com.google.common.base.Ascii) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) FIELD(javax.lang.model.element.ElementKind.FIELD) CONSTRUCTOR(javax.lang.model.element.ElementKind.CONSTRUCTOR) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ASTHelpers.canBeRemoved(com.google.errorprone.util.ASTHelpers.canBeRemoved) ASTHelpers.isSubtype(com.google.errorprone.util.ASTHelpers.isSubtype) HashMap(java.util.HashMap) MethodTree(com.sun.source.tree.MethodTree) JCAssign(com.sun.tools.javac.tree.JCTree.JCAssign) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) MemberSelectTree(com.sun.source.tree.MemberSelectTree) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) IdentifierTree(com.sun.source.tree.IdentifierTree) TreePathScanner(com.sun.source.util.TreePathScanner) NewClassTree(com.sun.source.tree.NewClassTree) Suppliers.typeFromString(com.google.errorprone.suppliers.Suppliers.typeFromString) Name(javax.lang.model.element.Name) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation) AnnotationTree(com.sun.source.tree.AnnotationTree) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Type(com.sun.tools.javac.code.Type) ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) TreePath(com.sun.source.util.TreePath) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) Collection(java.util.Collection)

Example 2 with CONSTRUCTOR

use of javax.lang.model.element.ElementKind.CONSTRUCTOR in project error-prone by google.

the class UnusedMethod method fixConstructors.

private void fixConstructors(ImmutableListMultimap<Symbol, TreePath> unusedConstructors, VisitorState state) {
    for (Map.Entry<Symbol, List<TreePath>> entry : asMap(unusedConstructors).entrySet()) {
        Symbol symbol = entry.getKey();
        List<TreePath> trees = entry.getValue();
        SuggestedFix.Builder fix = SuggestedFix.builder();
        int constructorCount = size(scope(symbol.members()).getSymbols(Symbol::isConstructor));
        int finalFields = size(scope(symbol.members()).getSymbols(s -> s.getKind().equals(FIELD) && s.getModifiers().contains(FINAL)));
        boolean fixable;
        if (constructorCount == trees.size()) {
            fix.postfixWith(getLast(trees).getLeaf(), format("private %s() {}", symbol.getSimpleName()));
            fixable = finalFields == 0;
        } else {
            fixable = true;
        }
        String message = String.format("Constructor '%s' is never used.", symbol.getSimpleName());
        trees.forEach(t -> fix.merge(replaceIncludingComments(t, "", state)));
        state.reportMatch(buildDescription(trees.get(0).getLeaf()).addFix(fixable ? fix.build() : emptyFix()).setMessage(message).build());
    }
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) Modifier(javax.lang.model.element.Modifier) SuggestedFixes.replaceIncludingComments(com.google.errorprone.fixes.SuggestedFixes.replaceIncludingComments) MoreAnnotations.asStrings(com.google.errorprone.util.MoreAnnotations.asStrings) ASTHelpers.isGeneratedConstructor(com.google.errorprone.util.ASTHelpers.isGeneratedConstructor) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ImmutableListMultimap.toImmutableListMultimap(com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap) ASTHelpers.shouldKeep(com.google.errorprone.util.ASTHelpers.shouldKeep) AssignmentTree(com.sun.source.tree.AssignmentTree) FINAL(javax.lang.model.element.Modifier.FINAL) IdentifierTree(com.sun.source.tree.IdentifierTree) Map(java.util.Map) Supplier(com.google.errorprone.suppliers.Supplier) Suppliers.typeFromString(com.google.errorprone.suppliers.Suppliers.typeFromString) MoreAnnotations.getAnnotationValue(com.google.errorprone.util.MoreAnnotations.getAnnotationValue) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) TreePath(com.sun.source.util.TreePath) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Collection(java.util.Collection) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) Iterables.getLast(com.google.common.collect.Iterables.getLast) MemberSelectTree(com.sun.source.tree.MemberSelectTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) String.format(java.lang.String.format) TreeScanner(com.sun.source.util.TreeScanner) List(java.util.List) SuggestedFix.emptyFix(com.google.errorprone.fixes.SuggestedFix.emptyFix) CompilationUnitTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher) Description(com.google.errorprone.matchers.Description) Multimaps.asMap(com.google.common.collect.Multimaps.asMap) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) ASTHelpers.scope(com.google.errorprone.util.ASTHelpers.scope) Type(com.sun.tools.javac.code.Type) SERIALIZATION_METHODS(com.google.errorprone.matchers.Matchers.SERIALIZATION_METHODS) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) Iterables.size(com.google.common.collect.Iterables.size) VisitorState(com.google.errorprone.VisitorState) Kind(com.sun.source.tree.Tree.Kind) NewClassTree(com.sun.source.tree.NewClassTree) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) BugPattern(com.google.errorprone.BugPattern) JCAssign(com.sun.tools.javac.tree.JCTree.JCAssign) TreePathScanner(com.sun.source.util.TreePathScanner) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) Name(javax.lang.model.element.Name) Ascii(com.google.common.base.Ascii) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) FIELD(javax.lang.model.element.ElementKind.FIELD) CONSTRUCTOR(javax.lang.model.element.ElementKind.CONSTRUCTOR) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ASTHelpers.canBeRemoved(com.google.errorprone.util.ASTHelpers.canBeRemoved) ASTHelpers.isSubtype(com.google.errorprone.util.ASTHelpers.isSubtype) TreePath(com.sun.source.util.TreePath) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) List(java.util.List) Suppliers.typeFromString(com.google.errorprone.suppliers.Suppliers.typeFromString) Map(java.util.Map) Multimaps.asMap(com.google.common.collect.Multimaps.asMap) HashMap(java.util.HashMap)

Aggregations

Ascii (com.google.common.base.Ascii)2 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)2 ImmutableListMultimap (com.google.common.collect.ImmutableListMultimap)2 ImmutableListMultimap.toImmutableListMultimap (com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 ImmutableSet.toImmutableSet (com.google.common.collect.ImmutableSet.toImmutableSet)2 Iterables.getLast (com.google.common.collect.Iterables.getLast)2 Iterables.size (com.google.common.collect.Iterables.size)2 Multimaps.asMap (com.google.common.collect.Multimaps.asMap)2 BugPattern (com.google.errorprone.BugPattern)2 WARNING (com.google.errorprone.BugPattern.SeverityLevel.WARNING)2 VisitorState (com.google.errorprone.VisitorState)2 CompilationUnitTreeMatcher (com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher)2 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)2 SuggestedFix.emptyFix (com.google.errorprone.fixes.SuggestedFix.emptyFix)2 SuggestedFixes.replaceIncludingComments (com.google.errorprone.fixes.SuggestedFixes.replaceIncludingComments)2 Description (com.google.errorprone.matchers.Description)2 SERIALIZATION_METHODS (com.google.errorprone.matchers.Matchers.SERIALIZATION_METHODS)2 Supplier (com.google.errorprone.suppliers.Supplier)2 Suppliers.typeFromString (com.google.errorprone.suppliers.Suppliers.typeFromString)2