-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce JUnitSingleArguments
bug checker
#816
Open
Venorcis
wants to merge
4
commits into
master
Choose a base branch
from
vkoeman/junit-arguments-single
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
...-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArguments.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ExpressionTree> 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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
...ne-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitSingleArgumentsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
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( | ||
Venorcis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"A.java", | ||
"import static java.util.Objects.requireNonNull;", | ||
"import static java.util.function.Function.identity;", | ||
"import static org.junit.jupiter.params.provider.Arguments.arguments;", | ||
"", | ||
"class A {", | ||
" void m() {", | ||
" // BUG: Diagnostic contains:", | ||
" arguments();", | ||
" // BUG: Diagnostic contains:", | ||
" arguments(1);", | ||
" arguments(1,2);", | ||
"", | ||
" identity();", | ||
" requireNonNull(null);", | ||
" }", | ||
"}") | ||
.doTest(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would cause a compilation error w.r.t. the return type, right? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wasn't sure how we deal with the fix suggestions. AFAIK not all suggestions necessarily lead to directly compiling code? We can ofc. remove it here and just flag instead 🤷🏻♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We try either produce compilable code or only flag the issue, with a strong preference for the former (as the latter really introduces quite a bit more friction). That said, especially some of the Refaster rules can in special circumstances break the code.
For this case we could:
JUnitValueSource
.(But that's considerably more complicated than the current proposal, so if you're like "uuuuuh", I get that. Don't mind having a stab; would just take a bit of time.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah understood. In the most common use case we 'only' need to replace
<Arguments>
with<T>
in the method definition. Perhaps it's relatively easy to add the suggestion for this use case and still resort to flagging any other occurrences (they would be weird but you never know 😛 ).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, that's the lines along which I'm thinking 👍
(Both inside Picnic and for the upcoming integration test framework against open-source repos we run Error Prone in a loop until it no longer makes any changes, which can only work if each intermediate state compiles successfully.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've looked a bit closer at this topic, and the logic in
JUnitValueSource
shows that there are quite a lot of details to consider:Arguments
can be wrapped in a top-level collection/stream/array.MonadType<Arguments>
orArguments[]
toMonadType<Object>
orObject[]
, but ideally we're more specific.Arguments
instances have exactly one value can we do the unwrapping (in case of variability we should likely emit a separate warning).JUnitValueSource
.I'm likely missing a few other details. Happy to dive deeper into this, but it'll be a while before I find the time to really sit down for this.