use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class ASTHelpersFindSuperMethodsTest method findSuperMethods_findsAllMethodsInTheHierarchy.
@Test
public void findSuperMethods_findsAllMethodsInTheHierarchy() {
MethodSymbol fooOfNorf = scanner.getMethod("Norf", "foo");
MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo");
MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo");
MethodSymbol fooOfQuux = scanner.getMethod("Foo", "foo");
assertThat(findSuperMethods(fooOfNorf)).isEqualTo(ImmutableList.of(fooOfBaz, fooOfBar, fooOfQuux));
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class IncompatibleArgumentType method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree methodInvocationTree, VisitorState state) {
// example:
// class Foo<A> {
// <B> void bar(@CompatibleWith("A") Object o, @CompatibleWith("B") Object o2) {}
// }
// new Foo<Integer>().<String>bar(1, "a');
// A Type substitution capturing <Integer> on Foo and <String> on bar(Object,Object);
Type calledMethodType = ASTHelpers.getType(methodInvocationTree.getMethodSelect());
// A Type substitution capturing <Integer> on Foo
Type calledClazzType = ASTHelpers.getReceiverType(methodInvocationTree);
List<? extends ExpressionTree> arguments = methodInvocationTree.getArguments();
// The unbound MethodSymbol for bar(), with type parameters <A> and <B>
MethodSymbol declaredMethod = ASTHelpers.getSymbol(methodInvocationTree);
if (arguments.isEmpty() || declaredMethod == null) {
return null;
}
List<RequiredType> requiredTypesAtCallSite = new ArrayList<>(Collections.nCopies(arguments.size(), null));
Types types = state.getTypes();
if (!populateTypesToEnforce(declaredMethod, calledMethodType, calledClazzType, requiredTypesAtCallSite, state)) {
// No annotations on this method, try the supers;
for (MethodSymbol method : ASTHelpers.findSuperMethods(declaredMethod, types)) {
if (populateTypesToEnforce(method, calledMethodType, calledClazzType, requiredTypesAtCallSite, state)) {
break;
}
}
}
reportAnyViolations(arguments, requiredTypesAtCallSite, state);
// We manually report ourselves, so we don't pass any errors up the chain.
return Description.NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class UnsafeFinalization method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
MethodSymbol sym = ASTHelpers.getSymbol(tree);
// Match invocations of static native methods.
if (sym == null || !sym.isStatic() || !Flags.asFlagSet(sym.flags()).contains(Flag.NATIVE)) {
return NO_MATCH;
}
// Find the enclosing method declaration where the invocation occurs.
MethodTree method = enclosingMethod(state);
if (method == null) {
return NO_MATCH;
}
// Don't check native methods called from static methods and constructors:
// static methods don't have an instance to finalize, and we shouldn't need to worry about
// finalization during construction.
MethodSymbol enclosing = ASTHelpers.getSymbol(method);
if (enclosing == null || enclosing.isStatic() || enclosing.isConstructor()) {
return NO_MATCH;
}
// Check if any arguments of the static native method are members (e.g. fields) of the enclosing
// class. We're only looking for cases where the static native uses state of the enclosing class
// that may become invalid after finalization.
ImmutableList<Symbol> arguments = tree.getArguments().stream().map(ASTHelpers::getSymbol).filter(x -> x != null).collect(toImmutableList());
if (arguments.stream().filter(x -> EnumSet.of(TypeKind.INT, TypeKind.LONG).contains(state.getTypes().unboxedTypeOrType(x.asType()).getKind())).noneMatch(arg -> arg.isMemberOf(enclosing.enclClass(), state.getTypes()))) {
// no instance state is passed to the native method
return NO_MATCH;
}
if (arguments.stream().anyMatch(arg -> arg.getSimpleName().contentEquals("this") && arg.isMemberOf(enclosing.enclClass(), state.getTypes()))) {
// the instance is passed to the native method
return NO_MATCH;
}
Symbol finalizeSym = getFinalizer(state, enclosing.enclClass());
if (finalizeSym.equals(enclosing)) {
// Don't check native methods called from within the implementation of finalize.
return NO_MATCH;
}
if (finalizeSym.enclClass().equals(state.getSymtab().objectType.asElement())) {
// Inheriting finalize from Object doesn't count.
return NO_MATCH;
}
boolean[] sawFence = { false };
new TreeScanner<Void, Void>() {
@Override
public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {
if (FENCE_MATCHER.matches(tree, state)) {
sawFence[0] = true;
}
return null;
}
}.scan(state.getPath().getCompilationUnit(), null);
if (sawFence[0]) {
// Ignore methods that contain a use of reachabilityFence.
return NO_MATCH;
}
return describeMatch(tree);
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class ProvidesNull method matchReturn.
/**
* Matches explicit "return null" statements in methods annotated with {@code @Provides} but not
* {@code @Nullable}. Suggests either annotating the method with {@code @Nullable} or throwing a
* {@link RuntimeException} instead.
*/
// TODO(eaftan): Use nullness dataflow analysis when it's ready
@Override
public Description matchReturn(ReturnTree returnTree, VisitorState state) {
ExpressionTree returnExpression = returnTree.getExpression();
if (returnExpression == null || returnExpression.getKind() != Kind.NULL_LITERAL) {
return Description.NO_MATCH;
}
TreePath path = state.getPath();
MethodTree enclosingMethod = null;
while (true) {
if (path == null || path.getLeaf() instanceof LambdaExpressionTree) {
return Description.NO_MATCH;
} else if (path.getLeaf() instanceof MethodTree) {
enclosingMethod = (MethodTree) path.getLeaf();
break;
} else {
path = path.getParentPath();
}
}
MethodSymbol enclosingMethodSym = ASTHelpers.getSymbol(enclosingMethod);
if (enclosingMethodSym == null) {
return Description.NO_MATCH;
}
if (!ASTHelpers.hasAnnotation(enclosingMethodSym, "dagger.Provides", state) || ASTHelpers.hasDirectAnnotationWithSimpleName(enclosingMethodSym, "Nullable")) {
return Description.NO_MATCH;
}
Fix addNullableFix = SuggestedFix.builder().prefixWith(enclosingMethod, "@Nullable\n").addImport("javax.annotation.Nullable").build();
CatchTree enclosingCatch = ASTHelpers.findEnclosingNode(state.getPath(), CatchTree.class);
if (enclosingCatch == null) {
// If not in a catch block, suggest adding @Nullable first, then throwing an exception.
Fix throwRuntimeExceptionFix = SuggestedFix.replace(returnTree, "throw new RuntimeException();");
return buildDescription(returnTree).addFix(addNullableFix).addFix(throwRuntimeExceptionFix).build();
} else {
// If in a catch block, suggest throwing an exception first, then adding @Nullable.
String replacement = String.format("throw new RuntimeException(%s);", enclosingCatch.getParameter().getName());
Fix throwRuntimeExceptionFix = SuggestedFix.replace(returnTree, replacement);
return buildDescription(returnTree).addFix(throwRuntimeExceptionFix).addFix(addNullableFix).build();
}
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class RefasterRuleBuilderScanner method visitMethod.
@Override
public Void visitMethod(MethodTree tree, Void v) {
try {
VisitorState state = new VisitorState(context);
logger.log(FINE, "Discovered method with name {0}", tree.getName());
if (ASTHelpers.hasAnnotation(tree, Placeholder.class, state)) {
checkArgument(tree.getModifiers().getFlags().contains(Modifier.ABSTRACT), "@Placeholder methods are expected to be abstract");
UTemplater templater = new UTemplater(context);
ImmutableMap.Builder<UVariableDecl, ImmutableClassToInstanceMap<Annotation>> params = ImmutableMap.builder();
for (VariableTree param : tree.getParameters()) {
params.put(templater.visitVariable(param, null), UTemplater.annotationMap(ASTHelpers.getSymbol(param)));
}
MethodSymbol sym = ASTHelpers.getSymbol(tree);
placeholderMethods.put(sym, PlaceholderMethod.create(tree.getName(), templater.template(sym.getReturnType()), params.build(), UTemplater.annotationMap(sym)));
} else if (ASTHelpers.hasAnnotation(tree, BeforeTemplate.class, state)) {
checkState(afterTemplates.isEmpty(), "BeforeTemplate must come before AfterTemplate");
Template<?> template = UTemplater.createTemplate(context, tree);
beforeTemplates.add(template);
if (template instanceof BlockTemplate) {
context.put(UTemplater.REQUIRE_BLOCK_KEY, /* data= */
true);
}
} else if (ASTHelpers.hasAnnotation(tree, AfterTemplate.class, state)) {
afterTemplates.add(UTemplater.createTemplate(context, tree));
} else if (tree.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
throw new IllegalArgumentException("Placeholder methods must have @Placeholder, but abstract method does not: " + tree);
}
return null;
} catch (Throwable t) {
throw new RuntimeException("Error analysing: " + tree.getName(), t);
}
}
Aggregations