-
Notifications
You must be signed in to change notification settings - Fork 57
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
fix(LambdaBlockToExpression): convert lambda with method invocation in assertThrows as well #245
base: main
Are you sure you want to change the base?
fix(LambdaBlockToExpression): convert lambda with method invocation in assertThrows as well #245
Conversation
Welcome back! :) I've changed the way your PR uses the recipe dependencies such that it's more in line with what we use elsewhere; also briefly stepped through with a debugger and noticed indeed that the recipe isn't triggered, and not yet clear why. |
It's not converted because of this block rewrite-static-analysis/src/main/java/org/openrewrite/staticanalysis/LambdaBlockToExpression.java Lines 88 to 108 in f1e53d2
Not sure how much we can improve this here without potentially breaking things elsewhere. 🤔 |
Fun puzzle, thanks! I think it would be fixed with 1ac607f |
@knutwannheden would you agree with the isolated change in 1ac607f ? I know we've been careful where we convert blocks and remove type casts, but I feel this minimal change might add a lot more reductions without additional risk that I can see now. |
I wouldn't necessarily merge the tests we have here now, as I'd prefer to keep the tests in rewrite-static-analysis free from dependencies, but it did help bring to light why were not replacing these instances, so thanks for that @timo-abele ! |
Hmm, discriminating by "same number of arguments" solves my use case (thank you so much!), because it excludes the problematic case from #162
whereas the heterogeneous
would be included. However, a hypothetical
would be included again when it shouldn't be. Maybe we should instead discriminate by "The parameter at the position where the lambda is should always have the same type"? |
That seems better indeed, and thanks for noticing that potential issue. Would you want to wire that up yourself? |
I've sketched something up, all tests run through but please review diligently I ended up rewriting more then I planned. |
@Override | ||
public void defaults(RecipeSpec spec) { | ||
spec.recipe(new LambdaBlockToExpression()) | ||
.parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true)); | ||
.parser(JavaParser.fromJavaVersion() | ||
.classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.10") |
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.
Since this dependency is only used for tests, we should make sure to not add it to src/main/resources
.
}) | ||
.orElse(false); | ||
} | ||
.orElse(Collections.emptyList()); |
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.
Rather than collecting all methods into a list, it would be more efficient to loop over them.
I am also saying this, because we should actually also be checking methods in super types and even default methods on implemented interfaces. But this can quickly get difficult, as I am not convinced that we will be reliable able to tell if a method is an override of some other method (and thus not an overload) when generics are involved. But once we cross that road, a recursive method which returns as soon as it finds a conflicting overload will be more efficient than first gathering all methods up front.
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 won't find time to finish this and have unassigned me. I trust your judgement that not collecting makes a enough of a difference to justify the loss in readability. I found the previous version very hard to get into (at first I thought it map
s over the list elements, but it is always over the Optional
):
rewrite-static-analysis/src/main/java/org/openrewrite/staticanalysis/LambdaBlockToExpression.java
Lines 80 to 97 in e57dac0
String methodName = methodType.getName(); | |
return Optional.of(methodType) | |
.map(JavaType.Method::getDeclaringType) | |
.filter(JavaType.Class.class::isInstance) | |
.map(JavaType.Class.class::cast) | |
.map(JavaType.Class::getMethods) | |
.map(methods -> { | |
int overloadingCount = 0; | |
for (JavaType.Method dm : methods) { | |
if (dm.getName().equals(methodName)) { | |
if (++overloadingCount > 1) { | |
return true; | |
} | |
} | |
} | |
return false; | |
}) | |
.orElse(false); |
MethodsOfType
can stay: rewrite-static-analysis/src/main/java/org/openrewrite/staticanalysis/LambdaBlockToExpression.java
Lines 113 to 118 in 758e7cf
List<JavaType.Method> methodsOfType = Optional.of(methodType) | |
.map(JavaType.Method::getDeclaringType) | |
.filter(JavaType.Class.class::isInstance) | |
.map(JavaType.Class.class::cast) | |
.map(JavaType.Class::getMethods) | |
.orElse(Collections.emptyList()); |
getMethods
) and Collections.emptyList()
is a constant, I think it makes no difference in performance while neatly separating the optional stream from the loop over the elements.
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.
Yes, you are right, there is no additional list being created here. I was already thinking ahead for the use case with inherited method declarations. But let's forget about that for the moment then (a bug will probably get reported at some point).
What's changed?
This PR will enable the transformation of lambdas with method invocation as body within assertThrows, a feature that unexpectedly wasn't fixed with #241.
What's your motivation?
Fixes #236
Anything in particular you'd like reviewers to focus on?
Anyone you would like to review specifically?
@timtebeek
Have you considered any alternatives or workarounds?
Any additional context
Checklist