-
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
Improve Optional#orElse{,Get}
support
#1283
Conversation
Looks good. All 18 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.
Some context.
/** | ||
* Tells whether the given expression contains anything other than a literal or a (possibly | ||
* dereferenced) variable or constant. | ||
*/ | ||
private static boolean requiresComputation(ExpressionTree tree) { | ||
return !(tree instanceof IdentifierTree | ||
|| tree instanceof LiteralTree | ||
|| (tree instanceof MemberSelectTree memberSelect | ||
&& !requiresComputation(memberSelect.getExpression())) | ||
|| ASTHelpers.constValue(tree) != null); | ||
} |
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.
Instead of two not-quite-complimentary implementations, all logic now lives in the RequiresComputation
matcher.
// XXX: This rule may introduce a compilation error: the `value` expression may reference a | ||
// non-effectively final variable, which is not allowed in the replacement lambda expression. | ||
// Review whether a `@Matcher` can be used to avoid this. |
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 observation was only moved from the Refaster rule to here. Fixing it is out of scope.
/** | ||
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the | ||
* fallback value is not the result of a trivial computation. | ||
* Prefer {@link Optional#orElse(Object)} over {@link Optional#orElseGet(Supplier)} if the | ||
* fallback value does not require non-trivial computation. | ||
*/ | ||
// XXX: This rule may introduce a compilation error: the `value` expression may reference a | ||
// non-effectively final variable, which is not allowed in the replacement lambda expression. | ||
// Review whether a `@Matcher` can be used to avoid this. | ||
// XXX: Once `MethodReferenceUsage` is "production ready", replace | ||
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and | ||
// reimplement the matcher accordingly). | ||
static final class OptionalOrElseGet<T> { | ||
// XXX: This rule is the counterpart to the `OptionalOrElseGet` bug checker. Once the | ||
// `MethodReferenceUsage` bug checker is "production ready", that bug checker may similarly be | ||
// replaced with a Refaster rule. | ||
static final class OptionalOrElse<T> { | ||
@BeforeTemplate | ||
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) { | ||
return optional.orElse(value); | ||
T before(Optional<T> optional, @NotMatches(RequiresComputation.class) T value) { | ||
return optional.orElseGet(() -> value); | ||
} | ||
|
||
@AfterTemplate | ||
T after(Optional<T> optional, T value) { | ||
return optional.orElseGet(() -> value); | ||
return optional.orElse(value); | ||
} | ||
} |
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.
Rule replaced: the old definition is absorbed into the bug checker, while the new rule implements complementary logic.
@SuppressWarnings({ | ||
"LexicographicalAnnotationAttributeListing" /* `key-*` entry must remain last. */, | ||
"NestedOptionals" /* This violation will be rewritten. */, | ||
"OptionalOrElse" /* Here `optional2` is a stand-in for expressions that may require computation. */, | ||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict" | ||
}) |
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, this is getting messy. Maybe those key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict
entries should start with zzz-
or something.
@@ -27,6 +28,7 @@ void identification() { | |||
" optional.orElse(string);", | |||
" optional.orElse(this.string);", | |||
" optional.orElse(Refaster.anyOf(\"constant\", \"another\"));", | |||
" Optional.<Supplier<String>>empty().orElse(() -> \"constant\");", |
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.
New test for the case that triggered this PR, observed with Picnic-internal 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.
To be clearer: previously the bug checker would not see the lambda expression as a trivial computation, while the Refaster rule would. In this context the latter was right.
Looks good. All 18 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
1 similar comment
Looks good. All 18 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.
More context.
" OutputStream negative9() {", | ||
" return System.out;", |
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 new test is to cover existing code that was previously untested. I filed hcoles/pitest#1341 Doh.
" }", | ||
"", | ||
" int negative6() {", | ||
" return 1 * 2;", |
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.
Previously the bug checker would see this as a trivial computation, but not the Refaster rule. The former was right.
@@ -27,6 +28,7 @@ void identification() { | |||
" optional.orElse(string);", | |||
" optional.orElse(this.string);", | |||
" optional.orElse(Refaster.anyOf(\"constant\", \"another\"));", | |||
" Optional.<Supplier<String>>empty().orElse(() -> \"constant\");", |
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.
To be clearer: previously the bug checker would not see the lambda expression as a trivial computation, while the Refaster rule would. In this context the latter was right.
Looks good. All 18 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
Looks good. All 16 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.
🚀 🚀
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.
LGTM! Nice improvements.
Summary of changes: - Consolidate the `OptionalOrElseGet` Refaster rule and the `OptionalOrElse` bug checker into the latter, keeping the best of both. - Rename the `OptionalOrElse` bug checker to `OptionalOrElseGet` to avoid confusion. - Replace the `IsLikelyTrivialComputation` matcher with the inverse `RequiresComputation` variant. - Introduce an `OptionalOrElse` Refaster rule that simplifies expressions in the "opposite direction".
af624dc
to
69d9d62
Compare
Quality Gate passedIssues Measures |
Looks good. All 16 mutations in this change were killed.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed. |
After upgrading 0.18.0 -> 0.19.0, with error-prone 2.35.1, Java Temurin-21.0.5+11, Apache Maven 3.9.9, I'm getting:
which seems to be related to this change. |
@pzygielo interesting. Do you have a stack trace/example code/reproducer? Happy to take a look! |
Unfortunately stack trace dumped by maven contains only maven calls, I can't see anything from javac there. I'm in the middle of preparation of minimal reproducer from the bigger project I see this in. Will share of course. |
Sometimes passing |
|
Perhaps |
Suggested commit message: