Search in sources :

Example 16 with MethodSymbol

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

the class CheckReturnValue method matchMethod.

/**
   * Validate {@link javax.annotation.CheckReturnValue} and {@link CanIgnoreReturnValue} usage on
   * methods.
   *
   * <p>The annotations should not both be appled to the same method.
   *
   * <p>The annotations should not be applied to void-returning methods. Doing so makes no sense,
   * because there is no return value to check.
   */
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    MethodSymbol method = ASTHelpers.getSymbol(tree);
    boolean checkReturn = hasDirectAnnotationWithSimpleName(method, CHECK_RETURN_VALUE);
    boolean canIgnore = hasAnnotation(method, CanIgnoreReturnValue.class, state);
    if (checkReturn && canIgnore) {
        return buildDescription(tree).setMessage(String.format(BOTH_ERROR, "method")).build();
    }
    String annotationToValidate;
    if (checkReturn) {
        annotationToValidate = javax.annotation.CheckReturnValue.class.getSimpleName();
    } else if (canIgnore) {
        annotationToValidate = CanIgnoreReturnValue.class.getSimpleName();
    } else {
        return Description.NO_MATCH;
    }
    if (method.getKind() != ElementKind.METHOD) {
        // skip contructors (which javac thinks are void-returning)
        return Description.NO_MATCH;
    }
    if (!ASTHelpers.isVoidType(method.getReturnType(), state)) {
        return Description.NO_MATCH;
    }
    String message = String.format("@%s may not be applied to void-returning methods", annotationToValidate);
    return buildDescription(tree).setMessage(message).build();
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol)

Example 17 with MethodSymbol

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

the class DescendantOf method matches.

@Override
public boolean matches(ExpressionTree expressionTree, VisitorState state) {
    Symbol sym = ASTHelpers.getSymbol(expressionTree);
    if (sym == null) {
        return false;
    }
    if (!(sym instanceof MethodSymbol)) {
        throw new IllegalArgumentException("DescendantOf matcher expects a method call but found " + sym.getClass() + ". Expression: " + expressionTree);
    }
    if (sym.isStatic()) {
        return false;
    }
    if (methodName.equals(sym.toString())) {
        Type accessedReferenceType = sym.owner.type;
        Type collectionType = state.getTypeFromString(fullClassName);
        if (collectionType != null) {
            return state.getTypes().isSubtype(accessedReferenceType, state.getTypes().erasure(collectionType));
        }
    }
    return false;
}
Also used : Type(com.sun.tools.javac.code.Type) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) Symbol(com.sun.tools.javac.code.Symbol)

Example 18 with MethodSymbol

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

the class TypeParameterUnusedInFormals method matchMethod.

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
    MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree);
    if (methodSymbol == null) {
        return Description.NO_MATCH;
    }
    // Only match methods where the return type is just a type parameter.
    // e.g. the following is OK: <T> List<T> newArrayList();
    TypeVar retType;
    switch(methodSymbol.getReturnType().getKind()) {
        case TYPEVAR:
            retType = (TypeVar) methodSymbol.getReturnType();
            break;
        default:
            return Description.NO_MATCH;
    }
    if (!methodSymbol.equals(retType.tsym.owner)) {
        return Description.NO_MATCH;
    }
    // e.g.: <T extends Enum<T>> T unsafeEnumDeserializer();
    if (retType.bound != null && TypeParameterFinder.visit(retType.bound).contains(retType.tsym)) {
        return Description.NO_MATCH;
    }
    // e.g.: <T> T noop(T t);
    for (VarSymbol formalParam : methodSymbol.getParameters()) {
        if (TypeParameterFinder.visit(formalParam.type).contains(retType.tsym)) {
            return Description.NO_MATCH;
        }
    }
    return describeMatch(tree);
}
Also used : TypeVar(com.sun.tools.javac.code.Type.TypeVar) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol)

Example 19 with MethodSymbol

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

the class UnnecessaryTypeArgument method check.

private Description check(Tree tree, List<? extends Tree> arguments, VisitorState state) {
    Symbol sym = ASTHelpers.getSymbol(tree);
    if (!(sym instanceof MethodSymbol)) {
        return Description.NO_MATCH;
    }
    MethodSymbol methodSymbol = (MethodSymbol) sym;
    int expected = methodSymbol.getTypeParameters().size();
    int actual = arguments.size();
    if (actual <= expected) {
        return Description.NO_MATCH;
    }
    for (MethodSymbol superMethod : ASTHelpers.findSuperMethods(methodSymbol, state.getTypes())) {
        if (!superMethod.getTypeParameters().isEmpty()) {
            // two types.
            return Description.NO_MATCH;
        }
    }
    return describeMatch(tree, buildFix(tree, arguments, state));
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) Symbol(com.sun.tools.javac.code.Symbol)

Example 20 with MethodSymbol

use of com.sun.tools.javac.code.Symbol.MethodSymbol 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);
    VariableTree paramTree = ASTHelpers.findEnclosingNode(state.getPath(), VariableTree.class);
    MethodSymbol declaredMethod = ASTHelpers.getSymbol(methodTree);
    // We're disallowing tags on varargs methods for now, but we may revisit it in the future.
    if (declaredMethod.isVarArgs() && Iterables.getLast(methodTree.getParameters()) == paramTree) {
        return describeWithMessage(annoTree, "@CompatibleWith can't be used on a varargs parameter");
    }
    // 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) VariableTree(com.sun.source.tree.VariableTree) ArrayList(java.util.ArrayList) TypeVariableSymbol(com.sun.tools.javac.code.Symbol.TypeVariableSymbol) CompatibleWith(com.google.errorprone.annotations.CompatibleWith)

Aggregations

MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)57 Symbol (com.sun.tools.javac.code.Symbol)24 Type (com.sun.tools.javac.code.Type)22 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)18 MethodTree (com.sun.source.tree.MethodTree)15 Tree (com.sun.source.tree.Tree)11 TypeSymbol (com.sun.tools.javac.code.Symbol.TypeSymbol)11 ExpressionTree (com.sun.source.tree.ExpressionTree)10 VarSymbol (com.sun.tools.javac.code.Symbol.VarSymbol)10 ArrayList (java.util.ArrayList)10 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)9 ClassTree (com.sun.source.tree.ClassTree)7 VariableTree (com.sun.source.tree.VariableTree)7 MethodType (com.sun.tools.javac.code.Type.MethodType)7 Types (com.sun.tools.javac.code.Types)7 IdentifierTree (com.sun.source.tree.IdentifierTree)6 MemberSelectTree (com.sun.source.tree.MemberSelectTree)6 JCTree (com.sun.tools.javac.tree.JCTree)6 VisitorState (com.google.errorprone.VisitorState)5 Description (com.google.errorprone.matchers.Description)5