Search in sources :

Example 91 with MethodSymbol

use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.

the class FunctionalInterfaceClash method matchClass.

@Override
public Description matchClass(ClassTree tree, VisitorState state) {
    ClassSymbol origin = getSymbol(tree);
    Types types = state.getTypes();
    // collect declared and inherited methods whose signature contains a functional interface
    Multimap<String, MethodSymbol> methods = HashMultimap.create();
    for (Symbol sym : types.membersClosure(getType(tree), /*skipInterface=*/
    false).getSymbols()) {
        if (!(sym instanceof MethodSymbol)) {
            continue;
        }
        if (isBugCheckerSuppressed((MethodSymbol) sym)) {
            continue;
        }
        MethodSymbol msym = (MethodSymbol) sym;
        if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
            continue;
        }
        if (msym.isConstructor() && !msym.owner.equals(origin)) {
            continue;
        }
        methods.put(functionalInterfaceSignature(state, msym), msym);
    }
    // (don't report clashes between inherited members)
    for (Tree member : tree.getMembers()) {
        if (!(member instanceof MethodTree)) {
            continue;
        }
        MethodSymbol msym = getSymbol((MethodTree) member);
        if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
            continue;
        }
        Collection<MethodSymbol> clash = new ArrayList<>(methods.removeAll(functionalInterfaceSignature(state, msym)));
        // Ignore inherited methods that are overridden in the original class. Note that we have to
        // handle transitive inheritance explicitly to handle cases where the visibility of an
        // overridded method is expanded somewhere in the type hierarchy.
        Deque<MethodSymbol> worklist = new ArrayDeque<>();
        worklist.push(msym);
        clash.remove(msym);
        while (!worklist.isEmpty()) {
            MethodSymbol msym2 = worklist.removeFirst();
            ImmutableList<MethodSymbol> overrides = clash.stream().filter(m -> msym2.overrides(m, origin, types, /*checkResult=*/
            false)).collect(toImmutableList());
            worklist.addAll(overrides);
            clash.removeAll(overrides);
        }
        if (!clash.isEmpty()) {
            // ignore if there are overridden clashing methods in class
            if (ASTHelpers.findSuperMethod(msym, types).isPresent() && clash.stream().anyMatch(methodSymbol -> ASTHelpers.findSuperMethod(methodSymbol, types).isPresent())) {
                return NO_MATCH;
            }
            String message = "When passing lambda arguments to this function, callers will need a cast to" + " disambiguate with: " + clash.stream().map(m -> Signatures.prettyMethodSignature(origin, m)).collect(joining("\n    "));
            state.reportMatch(buildDescription(member).setMessage(message).build());
        }
    }
    return NO_MATCH;
}
Also used : Arrays(java.util.Arrays) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher) MethodTree(com.sun.source.tree.MethodTree) DiagnosticPosition(com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition) ASTHelpers.getType(com.google.errorprone.util.ASTHelpers.getType) Multimap(com.google.common.collect.Multimap) Deque(java.util.Deque) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ArrayList(java.util.ArrayList) VisitorState(com.google.errorprone.VisitorState) HashMultimap(com.google.common.collect.HashMultimap) ImmutableList(com.google.common.collect.ImmutableList) Signatures(com.google.errorprone.util.Signatures) BugPattern(com.google.errorprone.BugPattern) JDK(com.google.errorprone.BugPattern.Category.JDK) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) 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) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Collectors.joining(java.util.stream.Collectors.joining) List(com.sun.tools.javac.util.List) Types(com.sun.tools.javac.code.Types) CompletionFailure(com.sun.tools.javac.code.Symbol.CompletionFailure) Check(com.sun.tools.javac.comp.Check) Description(com.google.errorprone.matchers.Description) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) ArrayDeque(java.util.ArrayDeque) Collections(java.util.Collections) ASTHelpers(com.google.errorprone.util.ASTHelpers) Type(com.sun.tools.javac.code.Type) Types(com.sun.tools.javac.code.Types) MethodTree(com.sun.source.tree.MethodTree) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ASTHelpers.getSymbol(com.google.errorprone.util.ASTHelpers.getSymbol) Symbol(com.sun.tools.javac.code.Symbol) ArrayList(java.util.ArrayList) ArrayDeque(java.util.ArrayDeque) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree)

Example 92 with MethodSymbol

use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.

the class FutureReturnValueIgnored method matchReturn.

/**
 * Returning a type of Future from a lambda or method that returns Object loses the Future type,
 * which can result in suppressed errors or race conditions.
 */
@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
    Type objectType = Objects.requireNonNull(state.getTypeFromString("java.lang.Object"));
    Type futureType = Objects.requireNonNull(state.getTypeFromString("java.util.concurrent.Future"));
    Type resultType = ASTHelpers.getResultType(tree.getExpression());
    if (resultType == null) {
        return Description.NO_MATCH;
    }
    if (resultType.getKind() == TypeKind.NULL || resultType.getKind() == TypeKind.NONE) {
        return Description.NO_MATCH;
    }
    if (ASTHelpers.isSubtype(resultType, futureType, state)) {
        // Traverse enclosing nodes of this return tree until either a lambda or a Method is reached.
        for (Tree enclosing : state.getPath()) {
            if (enclosing instanceof MethodTree) {
                MethodTree methodTree = (MethodTree) enclosing;
                MethodSymbol symbol = ASTHelpers.getSymbol(methodTree);
                if (ASTHelpers.isSubtype(objectType, symbol.getReturnType(), state) && !isWhitelistedInterfaceMethod(symbol, state)) {
                    return buildDescription(tree).setMessage(String.format("Returning %s from method that returns %s. Errors from the returned future" + " may be ignored.", resultType, symbol.getReturnType())).build();
                } else {
                    break;
                }
            }
            if (enclosing instanceof LambdaExpressionTree) {
                LambdaExpressionTree lambdaTree = (LambdaExpressionTree) enclosing;
                if (isObjectReturningLambdaExpression(lambdaTree, state)) {
                    return buildDescription(tree).setMessage(String.format("Returning %s from method that returns Object. Errors from the returned" + " future will be ignored.", resultType)).build();
                } else {
                    break;
                }
            }
        }
    }
    return Description.NO_MATCH;
}
Also used : LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) Type(com.sun.tools.javac.code.Type) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ReturnTree(com.sun.source.tree.ReturnTree) MethodTree(com.sun.source.tree.MethodTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree)

Example 93 with MethodSymbol

use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.

the class CanonicalDuration method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    Api api;
    if (JAVA_TIME_MATCHER.matches(tree, state)) {
        api = Api.JAVA;
    } else if (JODA_MATCHER.matches(tree, state)) {
        api = Api.JODA;
    } else {
        return NO_MATCH;
    }
    if (tree.getArguments().size() != 1) {
        // TODO(cushon): ofSeconds w/ nano adjustment?
        return NO_MATCH;
    }
    Tree arg = getOnlyElement(tree.getArguments());
    if (!(arg instanceof LiteralTree)) {
        // don't inline constants
        return NO_MATCH;
    }
    Number value = constValue(arg, Number.class);
    if (value == null) {
        return NO_MATCH;
    }
    if (value.intValue() == 0) {
        switch(api) {
            case JODA:
                ExpressionTree receiver = getReceiver(tree);
                SuggestedFix fix;
                if (receiver == null) {
                    // static import of the method
                    fix = SuggestedFix.builder().addImport(api.getDurationFullyQualifiedName()).replace(tree, "Duration.ZERO").build();
                } else {
                    fix = SuggestedFix.replace(state.getEndPosition(getReceiver(tree)), state.getEndPosition(tree), ".ZERO");
                }
                return buildDescription(tree).setMessage("Duration can be expressed more clearly without units, as Duration.ZERO").addFix(fix).build();
            case JAVA:
                // don't rewrite e.g. `ofMillis(0)` to `ofDays(0)`
                return NO_MATCH;
        }
        throw new AssertionError(api);
    }
    MethodSymbol sym = getSymbol(tree);
    if (!METHOD_NAME_TO_UNIT.containsKey(sym.getSimpleName().toString())) {
        return NO_MATCH;
    }
    TemporalUnit unit = METHOD_NAME_TO_UNIT.get(sym.getSimpleName().toString());
    if (Objects.equals(BLACKLIST.get(unit), value.longValue())) {
        return NO_MATCH;
    }
    Duration duration = Duration.of(value.longValue(), unit);
    // largest unit that can be used to exactly express the duration.
    for (Map.Entry<ChronoUnit, Converter<Duration, Long>> entry : CONVERTERS.entrySet()) {
        ChronoUnit nextUnit = entry.getKey();
        if (unit.equals(nextUnit)) {
            // We reached the original unit, no simplification is possible.
            break;
        }
        Converter<Duration, Long> converter = entry.getValue();
        long nextValue = converter.convert(duration);
        if (converter.reverse().convert(nextValue).equals(duration)) {
            // We reached a larger than original unit that precisely expresses the duration, rewrite to
            // use it instead.
            String name = FACTORIES.get(api, nextUnit);
            String replacement = String.format("%s(%d%s)", name, nextValue, nextValue == ((int) nextValue) ? "" : "L");
            ExpressionTree receiver = getReceiver(tree);
            if (receiver == null) {
                // static import of the method
                SuggestedFix fix = SuggestedFix.builder().addStaticImport(api.getDurationFullyQualifiedName() + "." + name).replace(tree, replacement).build();
                return describeMatch(tree, fix);
            } else {
                return describeMatch(tree, SuggestedFix.replace(state.getEndPosition(receiver), state.getEndPosition(tree), "." + replacement));
            }
        }
    }
    return NO_MATCH;
}
Also used : TemporalUnit(java.time.temporal.TemporalUnit) Duration(java.time.Duration) LiteralTree(com.sun.source.tree.LiteralTree) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) LiteralTree(com.sun.source.tree.LiteralTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) Converter(com.google.common.base.Converter) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) ChronoUnit(java.time.temporal.ChronoUnit)

Example 94 with MethodSymbol

use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.

the class InexactVarargsConditional method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
    MethodSymbol sym = ASTHelpers.getSymbol(tree);
    if (!sym.isVarArgs()) {
        return NO_MATCH;
    }
    if (tree.getArguments().size() != sym.getParameters().size()) {
        // explicit varargs call with more actuals than formals
        return NO_MATCH;
    }
    Tree arg = getLast(tree.getArguments());
    if (!(arg instanceof ConditionalExpressionTree)) {
        return NO_MATCH;
    }
    Types types = state.getTypes();
    if (types.isArray(getType(arg))) {
        return NO_MATCH;
    }
    ConditionalExpressionTree cond = (ConditionalExpressionTree) arg;
    boolean trueIsArray = types.isArray(getType(cond.getTrueExpression()));
    if (!(trueIsArray ^ types.isArray(getType(cond.getFalseExpression())))) {
        return NO_MATCH;
    }
    SuggestedFix.Builder fix = SuggestedFix.builder();
    String qualified = SuggestedFixes.qualifyType(state, fix, types.elemtype(getLast(sym.getParameters()).asType()));
    Tree toFix = !trueIsArray ? cond.getTrueExpression() : cond.getFalseExpression();
    fix.prefixWith(toFix, String.format("new %s[] {", qualified)).postfixWith(toFix, "}");
    return describeMatch(tree, fix.build());
}
Also used : Types(com.sun.tools.javac.code.Types) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Tree(com.sun.source.tree.Tree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree)

Example 95 with MethodSymbol

use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.

the class InfiniteRecursion method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    if (tree.getBody() == null || tree.getBody().getStatements().size() != 1) {
        return NO_MATCH;
    }
    Tree statement = stripParentheses(getOnlyElement(tree.getBody().getStatements()));
    ExpressionTree expr = statement.accept(new SimpleTreeVisitor<ExpressionTree, Void>() {

        @Override
        public ExpressionTree visitExpressionStatement(ExpressionStatementTree tree, Void unused) {
            return tree.getExpression();
        }

        @Override
        public ExpressionTree visitReturn(ReturnTree tree, Void unused) {
            return tree.getExpression();
        }
    }, null);
    if (!(expr instanceof MethodInvocationTree)) {
        return NO_MATCH;
    }
    ExpressionTree select = ((MethodInvocationTree) expr).getMethodSelect();
    switch(select.getKind()) {
        case IDENTIFIER:
            break;
        case MEMBER_SELECT:
            ExpressionTree receiver = ((MemberSelectTree) select).getExpression();
            if (receiver.getKind() != Kind.IDENTIFIER) {
                return NO_MATCH;
            }
            if (!((IdentifierTree) receiver).getName().contentEquals("this")) {
                return NO_MATCH;
            }
            break;
        default:
            return NO_MATCH;
    }
    MethodSymbol sym = ASTHelpers.getSymbol(tree);
    if (sym == null || !sym.equals(ASTHelpers.getSymbol(expr))) {
        return NO_MATCH;
    }
    return describeMatch(statement);
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ReturnTree(com.sun.source.tree.ReturnTree) MethodTree(com.sun.source.tree.MethodTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) IdentifierTree(com.sun.source.tree.IdentifierTree) ReturnTree(com.sun.source.tree.ReturnTree)

Aggregations

MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)98 Symbol (com.sun.tools.javac.code.Symbol)35 Type (com.sun.tools.javac.code.Type)32 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)27 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)22 MethodTree (com.sun.source.tree.MethodTree)22 Tree (com.sun.source.tree.Tree)21 ArrayList (java.util.ArrayList)18 ExpressionTree (com.sun.source.tree.ExpressionTree)17 TypeSymbol (com.sun.tools.javac.code.Symbol.TypeSymbol)13 VarSymbol (com.sun.tools.javac.code.Symbol.VarSymbol)13 Description (com.google.errorprone.matchers.Description)11 ClassTree (com.sun.source.tree.ClassTree)11 VisitorState (com.google.errorprone.VisitorState)10 JCTree (com.sun.tools.javac.tree.JCTree)9 Types (com.sun.tools.javac.code.Types)8 BugPattern (com.google.errorprone.BugPattern)7 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)7 MemberSelectTree (com.sun.source.tree.MemberSelectTree)7 MethodType (com.sun.tools.javac.code.Type.MethodType)7