Compare commits

...

1 Commits

Author SHA1 Message Date
Stephan Schroevers
70e92eed39 WIP: Introduce Refaster IsNullable matcher
As-is the tests fail, since the analysis assumes (in general) that
parameters and method return types are nullable by default. For our
purposes we want a more "optimistic" implementation. See about modifying
the configuration, or (perhaps) delegating to NullAway instead.
2024-02-10 13:02:11 +01:00
3 changed files with 101 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.CompoundAssignmentTree;
import com.sun.source.tree.ExpressionTree;
@@ -361,7 +362,7 @@ public final class RedundantStringConversion extends BugChecker
return Optional.of(methodInvocation.getMethodSelect())
.filter(methodSelect -> methodSelect.getKind() == Kind.MEMBER_SELECT)
.map(methodSelect -> ((MemberSelectTree) methodSelect).getExpression())
.filter(expr -> !"super".equals(SourceCode.treeToString(expr, state)));
.filter(expr -> !ASTHelpers.isSuper(expr));
}
private static Optional<ExpressionTree> trySimplifyUnaryMethod(

View File

@@ -0,0 +1,30 @@
package tech.picnic.errorprone.refaster.matchers;
import com.google.errorprone.VisitorState;
import com.google.errorprone.dataflow.nullnesspropagation.Nullness;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.NullnessMatcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
/** A matcher of nullable expressions. */
public final class IsNullable implements Matcher<ExpressionTree> {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> DELEGATE = new NullnessMatcher(Nullness.NONNULL);
/** Instantiates a new {@link IsNullable} instance. */
public IsNullable() {}
@Override
public boolean matches(ExpressionTree tree, VisitorState state) {
return !DELEGATE.matches(tree, state) && !isSuper(tree);
}
private static boolean isSuper(Tree tree) {
return ASTHelpers.isSuper(tree)
|| (tree instanceof MethodInvocationTree
&& ASTHelpers.isSuper(((MethodInvocationTree) tree).getMethodSelect()));
}
}

View File

@@ -0,0 +1,69 @@
package tech.picnic.errorprone.refaster.matchers;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import com.google.errorprone.BugPattern;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
import org.junit.jupiter.api.Test;
final class IsNullableTest {
@Test
void matches() {
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Map;",
"",
"class A {",
" String negative1() {",
" return \"a\";",
" }",
"",
" String negative2() {",
" return negative1();",
" }",
"",
" char[] negative3() {",
" return \"a\".toCharArray();",
" }",
"",
" byte negative4() {",
" return (byte) 0;",
" }",
"",
" Integer negative5(Integer param) {",
" return param;",
" }",
"",
" Character positive1() {",
" // BUG: Diagnostic contains:",
" return null;",
" }",
"",
" Character positive2() {",
" // BUG: Diagnostic contains:",
" return positive1();",
" }",
"",
" Integer positive3(Map<String, Integer> map) {",
" // BUG: Diagnostic contains:",
" return map.get(\"foo\");",
" }",
"}")
.doTest();
}
/** A {@link BugChecker} that simply delegates to {@link IsNullable}. */
@BugPattern(summary = "Flags expressions matched by `IsNullable`", severity = ERROR)
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
private static final long serialVersionUID = 1L;
// XXX: This is a false positive reported by Checkstyle. See
// https://github.com/checkstyle/checkstyle/issues/10161#issuecomment-1242732120.
@SuppressWarnings("RedundantModifier")
public MatcherTestChecker() {
super(new IsNullable());
}
}
}