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();
}
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;
}
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);
}
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));
}
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)));
}
Aggregations