Skip to content

Commit b4e8eed

Browse files
graememorganError Prone Team
authored andcommitted
Remove AbstractMethodReturnsNull and inline its logic.
The two inheritors are sufficiently different that this isn't helping, and is counterproductive to what I'm about to do. PiperOrigin-RevId: 849999819
1 parent d6304e3 commit b4e8eed

File tree

3 files changed

+56
-99
lines changed

3 files changed

+56
-99
lines changed

core/src/main/java/com/google/errorprone/bugpatterns/AbstractAsyncTypeReturnsNull.java

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,53 +16,59 @@
1616

1717
package com.google.errorprone.bugpatterns;
1818

19-
import static com.google.common.base.Preconditions.checkNotNull;
19+
import static com.google.errorprone.matchers.Description.NO_MATCH;
2020
import static com.google.errorprone.util.ASTHelpers.findSuperMethods;
2121
import static com.google.errorprone.util.ASTHelpers.getSymbol;
22+
import static com.sun.source.tree.Tree.Kind.NULL_LITERAL;
2223

2324
import com.google.common.util.concurrent.Futures;
2425
import com.google.errorprone.VisitorState;
25-
import com.google.errorprone.fixes.Fix;
26+
import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher;
2627
import com.google.errorprone.fixes.SuggestedFix;
27-
import com.google.errorprone.matchers.Matcher;
28+
import com.google.errorprone.matchers.Description;
29+
import com.sun.source.tree.ExpressionTree;
2830
import com.sun.source.tree.MethodTree;
2931
import com.sun.source.tree.ReturnTree;
30-
import com.sun.tools.javac.code.Symbol.MethodSymbol;
31-
import java.util.Optional;
32+
import com.sun.source.tree.StatementTree;
33+
import com.sun.source.util.TreePath;
3234

3335
/**
3436
* Superclass for checks that {@code AsyncCallable} and {@code AsyncFunction} implementations do not
3537
* directly {@code return null}.
3638
*/
37-
abstract class AbstractAsyncTypeReturnsNull extends AbstractMethodReturnsNull {
39+
abstract class AbstractAsyncTypeReturnsNull extends BugChecker implements ReturnTreeMatcher {
40+
private final Class<?> asyncClass;
3841

3942
AbstractAsyncTypeReturnsNull(Class<?> asyncClass) {
40-
super(overridesMethodOfClass(asyncClass));
43+
this.asyncClass = asyncClass;
4144
}
4245

4346
@Override
44-
protected Optional<Fix> provideFix(ReturnTree tree) {
45-
return Optional.of(
46-
SuggestedFix.builder()
47-
.replace(tree.getExpression(), "immediateFuture(null)")
48-
.addStaticImport(Futures.class.getName() + ".immediateFuture")
49-
.build());
47+
public final Description matchReturn(ReturnTree tree, VisitorState state) {
48+
if (tree.getExpression() == null || tree.getExpression().getKind() != NULL_LITERAL) {
49+
return NO_MATCH;
50+
}
51+
TreePath path = state.getPath();
52+
while (path != null && path.getLeaf() instanceof StatementTree) {
53+
path = path.getParentPath();
54+
}
55+
if (path == null || !(path.getLeaf() instanceof MethodTree methodTree)) {
56+
return NO_MATCH;
57+
}
58+
if (findSuperMethods(getSymbol(methodTree), state.getTypes()).stream()
59+
.noneMatch(
60+
superMethod ->
61+
superMethod.owner != null
62+
&& superMethod.owner.getQualifiedName().contentEquals(asyncClass.getName()))) {
63+
return NO_MATCH;
64+
}
65+
return describeMatch(tree, provideFix(tree.getExpression()));
5066
}
5167

52-
private static Matcher<MethodTree> overridesMethodOfClass(Class<?> clazz) {
53-
checkNotNull(clazz);
54-
return new Matcher<MethodTree>() {
55-
@Override
56-
public boolean matches(MethodTree tree, VisitorState state) {
57-
MethodSymbol symbol = getSymbol(tree);
58-
for (MethodSymbol superMethod : findSuperMethods(symbol, state.getTypes())) {
59-
if (superMethod.owner != null
60-
&& superMethod.owner.getQualifiedName().contentEquals(clazz.getName())) {
61-
return true;
62-
}
63-
}
64-
return false;
65-
}
66-
};
68+
protected SuggestedFix provideFix(ExpressionTree tree) {
69+
return SuggestedFix.builder()
70+
.replace(tree, "immediateFuture(null)")
71+
.addStaticImport(Futures.class.getName() + ".immediateFuture")
72+
.build();
6773
}
6874
}

core/src/main/java/com/google/errorprone/bugpatterns/AbstractMethodReturnsNull.java

Lines changed: 0 additions & 62 deletions
This file was deleted.

core/src/main/java/com/google/errorprone/bugpatterns/ReturnsNullCollection.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,24 @@
1717
package com.google.errorprone.bugpatterns;
1818

1919
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
20+
import static com.google.errorprone.matchers.Description.NO_MATCH;
2021
import static com.google.errorprone.matchers.Matchers.allOf;
2122
import static com.google.errorprone.matchers.Matchers.anyOf;
2223
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
2324
import static com.google.errorprone.matchers.Matchers.methodReturns;
2425
import static com.google.errorprone.util.ASTHelpers.getSymbol;
26+
import static com.sun.source.tree.Tree.Kind.NULL_LITERAL;
2527

2628
import com.google.errorprone.BugPattern;
2729
import com.google.errorprone.VisitorState;
30+
import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher;
2831
import com.google.errorprone.dataflow.nullnesspropagation.TrustingNullnessAnalysis;
29-
import com.google.errorprone.fixes.Fix;
32+
import com.google.errorprone.matchers.Description;
3033
import com.google.errorprone.matchers.Matcher;
3134
import com.sun.source.tree.MethodTree;
3235
import com.sun.source.tree.ReturnTree;
33-
import java.util.Optional;
36+
import com.sun.source.tree.StatementTree;
37+
import com.sun.source.util.TreePath;
3438

3539
/**
3640
* Flags methods with collection return types which return {@code null} in some cases but don't
@@ -43,7 +47,7 @@
4347
"Method has a collection return type and returns {@code null} in some cases but does not"
4448
+ " annotate the method as @Nullable. See Effective Java 3rd Edition Item 54.",
4549
severity = SUGGESTION)
46-
public class ReturnsNullCollection extends AbstractMethodReturnsNull {
50+
public class ReturnsNullCollection extends BugChecker implements ReturnTreeMatcher {
4751

4852
private static boolean methodWithoutNullable(MethodTree tree, VisitorState state) {
4953
return !TrustingNullnessAnalysis.hasNullableAnnotation(getSymbol(tree));
@@ -58,12 +62,21 @@ private static boolean methodWithoutNullable(MethodTree tree, VisitorState state
5862
methodReturns(isSubtypeOf("com.google.common.collect.Table"))),
5963
ReturnsNullCollection::methodWithoutNullable);
6064

61-
public ReturnsNullCollection() {
62-
super(METHOD_RETURNS_COLLECTION_WITHOUT_NULLABLE_ANNOTATION);
63-
}
64-
6565
@Override
66-
protected Optional<Fix> provideFix(ReturnTree tree) {
67-
return Optional.empty();
66+
public final Description matchReturn(ReturnTree tree, VisitorState state) {
67+
if (tree.getExpression() == null || tree.getExpression().getKind() != NULL_LITERAL) {
68+
return NO_MATCH;
69+
}
70+
TreePath path = state.getPath();
71+
while (path != null && path.getLeaf() instanceof StatementTree) {
72+
path = path.getParentPath();
73+
}
74+
if (path == null || !(path.getLeaf() instanceof MethodTree methodTree)) {
75+
return NO_MATCH;
76+
}
77+
if (!METHOD_RETURNS_COLLECTION_WITHOUT_NULLABLE_ANNOTATION.matches(methodTree, state)) {
78+
return NO_MATCH;
79+
}
80+
return describeMatch(tree);
6881
}
6982
}

0 commit comments

Comments
 (0)