use of com.sun.source.tree.MethodTree in project error-prone by google.
the class CreatesDuplicateCallHeuristic method findArgumentsForOtherInstances.
/**
* Find all the other calls to {@code calledMethod} within the method (or class) which enclosed
* the original call.
*
* <p>We are interested in two different cases: 1) where there are other calls to the method we
* are calling; 2) declarations of the method we are calling (this catches the case when there is
* a recursive call with the arguments correctly swapped).
*
* @param calledMethod is the method call we are analysing for swaps
* @param currentNode is the tree node the method call occurred at
* @param state is the current visitor state
* @return a list containing argument lists for each call found
*/
private static List<List<Parameter>> findArgumentsForOtherInstances(MethodSymbol calledMethod, Tree currentNode, VisitorState state) {
Tree enclosingNode = ASTHelpers.findEnclosingNode(state.getPath(), MethodTree.class);
if (enclosingNode == null) {
enclosingNode = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
}
if (enclosingNode == null) {
return ImmutableList.of();
}
ImmutableList.Builder<List<Parameter>> resultBuilder = ImmutableList.builder();
new TreeScanner<Void, Void>() {
@Override
public Void visitMethodInvocation(MethodInvocationTree methodInvocationTree, Void aVoid) {
addToResult(ASTHelpers.getSymbol(methodInvocationTree), methodInvocationTree);
return super.visitMethodInvocation(methodInvocationTree, aVoid);
}
@Override
public Void visitNewClass(NewClassTree newClassTree, Void aVoid) {
addToResult(ASTHelpers.getSymbol(newClassTree), newClassTree);
return super.visitNewClass(newClassTree, aVoid);
}
@Override
public Void visitMethod(MethodTree methodTree, Void aVoid) {
MethodSymbol methodSymbol = ASTHelpers.getSymbol(methodTree);
if (methodSymbol != null) {
// if the method declared here is the one we are calling then add it
addToResult(methodSymbol, methodTree);
// if any supermethod of the one declared here is the one we are calling then add it
for (MethodSymbol superSymbol : ASTHelpers.findSuperMethods(methodSymbol, state.getTypes())) {
addToResult(superSymbol, methodTree);
}
}
return super.visitMethod(methodTree, aVoid);
}
private void addToResult(MethodSymbol foundSymbol, Tree tree) {
if (foundSymbol != null && Objects.equals(calledMethod, foundSymbol) && !currentNode.equals(tree)) {
resultBuilder.add(createParameterList(tree));
}
}
private ImmutableList<Parameter> createParameterList(Tree tree) {
if (tree instanceof MethodInvocationTree) {
return Parameter.createListFromExpressionTrees(((MethodInvocationTree) tree).getArguments());
}
if (tree instanceof NewClassTree) {
return Parameter.createListFromExpressionTrees(((NewClassTree) tree).getArguments());
}
if (tree instanceof MethodTree) {
return Parameter.createListFromVariableTrees(((MethodTree) tree).getParameters());
}
return ImmutableList.of();
}
}.scan(enclosingNode, null);
return resultBuilder.build();
}
use of com.sun.source.tree.MethodTree 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);
MethodSymbol declaredMethod = ASTHelpers.getSymbol(methodTree);
// 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)));
}
use of com.sun.source.tree.MethodTree in project error-prone by google.
the class ForOverrideChecker method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
MethodSymbol method = ASTHelpers.getSymbol(tree);
if (method == null) {
return Description.NO_MATCH;
}
Type currentClass = getOutermostClass(state);
if (method.isStatic() || method.isConstructor() || currentClass == null) {
return Description.NO_MATCH;
}
// allow super.foo() calls to @ForOverride methods from overriding methods
if (isSuperCall(currentClass, tree, state)) {
MethodTree currentMethod = findDirectMethod(state.getPath());
// currentMethod might be null if we are in a field initializer
if (currentMethod != null) {
// MethodSymbol.overrides doesn't check that names match, so we need to do that first.
if (currentMethod.getName().equals(method.name)) {
MethodSymbol currentMethodSymbol = ASTHelpers.getSymbol(currentMethod);
if (currentMethodSymbol.overrides(method, (TypeSymbol) method.owner, state.getTypes(), /* checkResult= */
true)) {
return Description.NO_MATCH;
}
}
}
}
List<MethodSymbol> overriddenMethods = getOverriddenMethods(state, method);
for (Symbol overriddenMethod : overriddenMethods) {
Type declaringClass = overriddenMethod.outermostClass().asType();
if (!declaringClass.equals(currentClass)) {
String customMessage = MESSAGE_BASE + "must not be invoked directly " + "(except by the declaring class, " + declaringClass + ")";
return buildDescription(tree).setMessage(customMessage).build();
}
}
return Description.NO_MATCH;
}
use of com.sun.source.tree.MethodTree in project error-prone by google.
the class DoubleBraceInitialization method matchNewClass.
@Override
public Description matchNewClass(NewClassTree tree, VisitorState state) {
ClassTree body = tree.getClassBody();
if (body == null) {
return NO_MATCH;
}
ImmutableList<? extends Tree> members = body.getMembers().stream().filter(m -> !(m instanceof MethodTree && ASTHelpers.isGeneratedConstructor((MethodTree) m))).collect(toImmutableList());
if (members.size() != 1) {
return NO_MATCH;
}
Tree member = Iterables.getOnlyElement(members);
if (!(member instanceof BlockTree)) {
return NO_MATCH;
}
BlockTree block = (BlockTree) member;
Optional<CollectionTypes> collectionType = Stream.of(CollectionTypes.values()).filter(type -> type.constructorMatcher.matches(tree, state)).findFirst();
if (!collectionType.isPresent()) {
return NO_MATCH;
}
Description.Builder description = buildDescription(tree);
collectionType.get().maybeFix(tree, state, block).ifPresent(description::addFix);
return description.build();
}
use of com.sun.source.tree.MethodTree in project error-prone by google.
the class InputStreamSlowMultibyteRead method maybeMatchReadByte.
private Description maybeMatchReadByte(MethodTree readByteMethod, VisitorState state) {
if (readByteMethod.getBody() != null) {
// Null-check for native/abstract overrides of read()
List<? extends StatementTree> statements = readByteMethod.getBody().getStatements();
if (statements.size() == 1) {
Tree tree = statements.get(0);
if (tree.getKind() == Kind.RETURN && ASTHelpers.constValue(((ReturnTree) tree).getExpression()) != null) {
return Description.NO_MATCH;
}
}
}
// Streams within JUnit test cases are likely to be OK as well.
TreePath enclosingPath = ASTHelpers.findPathFromEnclosingNodeToTopLevel(state.getPath(), ClassTree.class);
while (enclosingPath != null) {
ClassTree klazz = (ClassTree) enclosingPath.getLeaf();
if (JUnitMatchers.isTestCaseDescendant.matches(klazz, state) || hasAnnotation(JUnitMatchers.JUNIT4_RUN_WITH_ANNOTATION).matches(klazz, state)) {
return Description.NO_MATCH;
}
enclosingPath = ASTHelpers.findPathFromEnclosingNodeToTopLevel(enclosingPath, ClassTree.class);
}
return describeMatch(readByteMethod);
}
Aggregations