-
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 DirectReturn
check
#513
Conversation
Looks good. All 26 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
linkType = CUSTOM, | ||
severity = SUGGESTION, | ||
tags = SIMPLIFICATION) | ||
public final class DirectReturn extends BugChecker implements BlockTreeMatcher { |
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.
Naming-wise, "something something unnecessary assignment" may be nicer. But (a) we're not performing a flow analysis that flags all unnecessary variable assignments and (b) a name that accurately describes the subset covered would be quite unwieldy. Unless I'm just not creative enough, of course 🙃. Suggestions welcome.
Just realized: ideally we do not suggest inlining if (a) the variable assigned to is of a different type than the method's return type and (b) this difference may influence the return value. Prime example here is Mockito's nullary |
b3c41d7
to
120e418
Compare
Rebased and added a commit to cover this case. Did make it Mockito-specifc, because attempts at generalization became too contrived. |
Looks good. All 51 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
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.
Added one more commit.
@@ -49,7 +48,7 @@ | |||
public final class MockitoMockClassReference extends BugChecker |
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.
CC @Badbond: I renamed/moved some logic in this class.
public static Optional<MethodTree> findMethodExitedOnReturn(VisitorState state) { | ||
return Optional.ofNullable(state.findEnclosing(LambdaExpressionTree.class, MethodTree.class)) | ||
.filter(MethodTree.class::isInstance) | ||
.map(MethodTree.class::cast); | ||
} |
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 decided to move this out because it handles quite a gotcha; better to not duplicate this logic.
Looks good. All 51 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
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.
Flushing one comment I had. Will continue later today.
.addSourceLines( | ||
"A.java", | ||
"class A {", | ||
" void negative1(String a, Integer b) {}", |
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.
Might be good to add a test where one is a subtype of the other? (Will add this in a commit)
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.
The code itself and the added test cases were rather straightforward, nice work @Stephan202 👍
One more point about the exhaustiveness of the mockito exclusion, but I wouldn't expect more changes here as part of this PR. Hence I'm approving.
* <p>Inlining is generally safe, but in rare cases the operation may have a functional impact. | ||
* The sole case considered here is the inlining of a Mockito mock or spy construction without an | ||
* explicit type. In such a case the type created depends on context, such as the method's return | ||
* type. |
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.
Great to have added this exclusion. Are we sure the exclusion is exhaustive however? My guess is: probably never fully, but this is a best-effort solution that should handle the majority of EPS users.
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.
Nope, this is not exhaustive, unfortunately. I did play with some more generic code, but it became way more complex than I could justify for this feature. So in the end gave up on that idea.
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.
Tnx for the reviews!
* <p>Inlining is generally safe, but in rare cases the operation may have a functional impact. | ||
* The sole case considered here is the inlining of a Mockito mock or spy construction without an | ||
* explicit type. In such a case the type created depends on context, such as the method's return | ||
* type. |
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.
Nope, this is not exhaustive, unfortunately. I did play with some more generic code, but it became way more complex than I could justify for this feature. So in the end gave up on that idea.
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.
Really cool check 🚀.
Have some small comments and an extra test case or two. Let me know what you think 😄.
" return variable;", | ||
" }", | ||
"", | ||
" Object salienSpyTypeVariableDeclaration() {", |
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.
" Object salienSpyTypeVariableDeclaration() {", | |
" Object salientSpyTypeVariableDeclaration() {", |
" // BUG: Diagnostic contains:", | ||
" variable = \"foo\";", | ||
" return variable;", | ||
" }", |
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 think this is also an interesting case to add:
Supplier<String> redundantAssignmentInLambda() {
return () -> {
// BUG: Diagnostic contains:
String variable = toString();
return variable;
};
@@ -46,4 +50,33 @@ public static ImmutableList<MethodTree> findMethods(CharSequence methodName, Vis | |||
public static boolean methodExistsInEnclosingClass(CharSequence methodName, VisitorState state) { | |||
return !findMethods(methodName, state).isEmpty(); | |||
} | |||
|
|||
/** | |||
* Returns the {@link MethodTree} from which control flow would exit if there would be a {@code |
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.
* Returns the {@link MethodTree} from which control flow would exit if there would be a {@code | |
* Returns the {@link MethodTree} from which the control flow would exit if there would be a {@code |
Sounds a bit better to me 🤔.
Looks good. All 51 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
Aii, misclicked and merged instead of rebased 😅. |
Looks good. All 51 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
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.
Tnx; changes LGTM otherwise
@@ -46,4 +50,33 @@ public static ImmutableList<MethodTree> findMethods(CharSequence methodName, Vis | |||
public static boolean methodExistsInEnclosingClass(CharSequence methodName, VisitorState state) { | |||
return !findMethods(methodName, state).isEmpty(); | |||
} | |||
|
|||
/** | |||
* Returns the {@link MethodTree} from which the control flow would exit if there would be a |
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 think we should omit "the" here. (Cause this is not about a "definite" control flow.)
" }", | ||
" }", | ||
"", | ||
" Supplier<String> redundantAssignmentInLambda() {", |
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.
" Supplier<String> redundantAssignmentInLambda() {", | |
" Supplier<String> redundantAssignmentInsideLambda() {", |
Also matches the method above.
10ddbf3
to
2507a85
Compare
Applied and rebased. Will merge once 🟢, thanks for taking a look so quickly. |
Let's gooooo 🚀 |
Looks good. All 51 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
This PR replaces #1. I decided to pick this task up because the topic was raised after @rickie's recent Amsterdam JUG presentation. CC @SimonBaars.
Suggested commit message: