From 29bdf78481a86583cd0e1990e8c7eef3ece19aa7 Mon Sep 17 00:00:00 2001 From: Vincent Koeman Date: Fri, 6 Oct 2023 17:07:51 +0200 Subject: [PATCH] Introduce `JUnitSingleArguments` bug checker --- .../bugpatterns/JUnitSingleArguments.java | 50 +++++++++++++++++++ .../bugpatterns/JUnitSingleArgumentsTest.java | 26 ++++++++++ 2 files changed, 76 insertions(+) create mode 100644 error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArguments.java create mode 100644 error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArgumentsTest.java diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArguments.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArguments.java new file mode 100644 index 0000000000..9100456858 --- /dev/null +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArguments.java @@ -0,0 +1,50 @@ +package tech.picnic.errorprone.bugpatterns; + +import static com.google.errorprone.BugPattern.LinkType.CUSTOM; +import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION; +import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION; +import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import tech.picnic.errorprone.bugpatterns.util.SourceCode; + +/** + * A {@link BugChecker} that flags uses of {@link + * org.junit.jupiter.params.provider.Arguments#arguments(Object...)} with a single (or no) argument; + * in such cases the use of {@link org.junit.jupiter.params.provider.Arguments} is not required as a + * {@link java.util.stream.Stream} of objects can be directly provided to a {@link + * org.junit.jupiter.params.provider.MethodSource}. + */ +@AutoService(BugChecker.class) +@BugPattern( + summary = "JUnit arguments wrapping a single object are redundant", + link = BUG_PATTERNS_BASE_URL + "JUnitSingleArguments", + linkType = CUSTOM, + severity = SUGGESTION, + tags = SIMPLIFICATION) +public final class JUnitSingleArguments extends BugChecker implements MethodInvocationTreeMatcher { + private static final long serialVersionUID = 1L; + private static final Matcher ARGUMENTS_ARGUMENTS = + staticMethod().onClass("org.junit.jupiter.params.provider.Arguments").named("arguments"); + + /** Instantiates a new {@link JUnitSingleArguments} instance. */ + public JUnitSingleArguments() {} + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (ARGUMENTS_ARGUMENTS.matches(tree, state) && tree.getArguments().size() <= 1) { + return describeMatch(tree, SourceCode.unwrapMethodInvocation(tree, state)); + } + + return Description.NO_MATCH; + } +} diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArgumentsTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArgumentsTest.java new file mode 100644 index 0000000000..544b16a918 --- /dev/null +++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArgumentsTest.java @@ -0,0 +1,26 @@ +package tech.picnic.errorprone.bugpatterns; + +import com.google.errorprone.CompilationTestHelper; +import org.junit.jupiter.api.Test; + +final class JUnitSingleArgumentsTest { + @Test + void identification() { + CompilationTestHelper.newInstance(JUnitSingleArguments.class, getClass()) + .addSourceLines( + "A.java", + "import static org.junit.jupiter.params.provider.Arguments.arguments;", + "import java.util.stream.Stream;", + "", + "class A {", + " void m() {", + " // BUG: Diagnostic contains:", + " arguments();", + " // BUG: Diagnostic contains:", + " arguments(1);", + " arguments(1,2);", + " }", + "}") + .doTest(); + } +}