Search in sources :

Example 1 with CompatibleWith

use of com.google.errorprone.annotations.CompatibleWith 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)

Example 2 with CompatibleWith

use of com.google.errorprone.annotations.CompatibleWith in project error-prone by google.

the class IncompatibleArgumentType method populateTypesToEnforce.

@CheckReturnValue
private boolean populateTypesToEnforce(MethodSymbol declaredMethod, Type calledMethodType, Type calledReceiverType, List<RequiredType> requiredTypesAtCallSite, VisitorState state) {
    // We'll only search the first method in the hierarchy with an annotation.
    boolean found = false;
    com.sun.tools.javac.util.List<VarSymbol> params = declaredMethod.params();
    for (int i = 0; i < params.size(); i++) {
        VarSymbol varSymbol = params.get(i);
        CompatibleWith anno = ASTHelpers.getAnnotation(varSymbol, CompatibleWith.class);
        if (anno != null) {
            found = true;
            if (requiredTypesAtCallSite.size() <= i) {
                // void foo(String...); foo();
                break;
            }
            // Now we try and resolve the generic type argument in the annotation against the current
            // method call's projection of this generic type.
            RequiredType requiredType = resolveRequiredTypeForThisCall(state, calledMethodType, calledReceiverType, declaredMethod, anno.value());
            requiredTypesAtCallSite.set(i, requiredType);
        }
    }
    return found;
}
Also used : VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) CompatibleWith(com.google.errorprone.annotations.CompatibleWith) CheckReturnValue(javax.annotation.CheckReturnValue)

Aggregations

CompatibleWith (com.google.errorprone.annotations.CompatibleWith)2 MethodTree (com.sun.source.tree.MethodTree)1 VariableTree (com.sun.source.tree.VariableTree)1 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)1 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)1 TypeVariableSymbol (com.sun.tools.javac.code.Symbol.TypeVariableSymbol)1 VarSymbol (com.sun.tools.javac.code.Symbol.VarSymbol)1 ArrayList (java.util.ArrayList)1 CheckReturnValue (javax.annotation.CheckReturnValue)1