-
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
PrimitiveComparison: Retain type arguments if present #39
PrimitiveComparison: Retain type arguments if present #39
Conversation
@@ -37,7 +37,6 @@ | |||
*/ | |||
// XXX: Add more documentation. Explain how this is useful in the face of refactoring to more | |||
// specific types. | |||
// XXX: Change this checker's name? |
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.
Did not improve the naming, but suggest that we either improve the naming or delete this XXX 😄.
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.
Or keep the comment since it may still apply 🙃
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 shortly clarify, I did think about the XXX but think that the name is fine as it is.
So I removed the line to "start the discussion" because I feel that we can easily do the XXX by either removing it or coming up with an improvement 😄.
Some ideas: ComparatorUsage
, ComparatorPrimitive
, CanonicalComparatorUsage
.
WDYT?
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.
ComparatorUsage
and CanonicalComparatorUsage
are nice, but hint at something more generic. Let's keep the current name, at least in the context of the current PR.
@@ -77,23 +76,44 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState | |||
} | |||
|
|||
return getPotentiallyBoxedReturnType(tree.getArguments().get(0)) | |||
.flatMap(cmpType -> tryFix(tree, state, cmpType, isStatic)) | |||
.flatMap(cmpType -> tryMakeMethodCallMorePrecise(tree, cmpType, isStatic, state)) |
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.
Not entirely sure about the method name, but figured that we could be more clear than tryFix
here.
@@ -128,9 +148,6 @@ private static String getPreferredMethod(VisitorState state, Type cmpType, boole | |||
} | |||
} | |||
|
|||
// XXX: We drop explicitly specified generic type information. In case the number of type | |||
// arguments before and after doesn't match, that's for the better. But if we e.g. replace | |||
// `comparingLong` with `comparingInt`, then we should retain it. |
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 tests don't show such a replacement. Is this a realistic scenario that we (will) handle with this check?
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 tests convince me to approve, but some minor things are to improve here.
@@ -37,7 +37,6 @@ | |||
*/ | |||
// XXX: Add more documentation. Explain how this is useful in the face of refactoring to more | |||
// specific types. | |||
// XXX: Change this checker's name? |
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.
Or keep the comment since it may still apply 🙃
private static Optional<Fix> tryFix( | ||
MethodInvocationTree tree, VisitorState state, Type cmpType, boolean isStatic) { | ||
private static Optional<Fix> tryMakeMethodCallMorePrecise( | ||
MethodInvocationTree tree, Type cmpType, boolean isStatic, VisitorState state) { |
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.
(1) Why did we change the order? Isn't the VisitorState
much more important? Here and in the other methods.
(2) What was this renamed? Don't we still try to fix it?
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.
(1) It is sort of an "unwritten rule/convention". In both Error Prone and error-prone-support
the VisitorState
always comes last.
(2) IMO we can use the method name to better express what we are trying to do. The PrimitiveComparisonCheck
tries to improve multiple things and by changing the method name, we can make it more clear which part we are trying to fix in this method.
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.
(1) ✔️
(2) Not sure whether tryMakeMethodCallMorePrecise
is expressing anything well 🙃 But I also don't have a better suggestion right now. 🙂
.map(preferredMethodName -> suggestFix(tree, preferredMethodName, state)); | ||
} | ||
|
||
private static String getPreferredMethod(VisitorState state, Type cmpType, boolean isStatic) { | ||
private static String prefixWithTypeArgumentsIfNeeded( |
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 "if needed" part looks off to me. WDYT?
private static String prefixWithTypeArgumentsIfNeeded( | |
private static String mayPrefixWithTypeArguments( |
String optionalSecondTypeArgument = | ||
methodNameIsComparing ? ", " + cmpType.tsym.getSimpleName() : ""; | ||
return String.format( | ||
"<%s%s>%s", | ||
Util.treeToString(tree.getTypeArguments().get(0), state), | ||
optionalSecondTypeArgument, | ||
preferredMethodName); |
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 part feels pretty hacky. Why can't we join both potential type arguments?
String typeArgument =
Stream.concat(
Stream.of(Util.treeToString(tree.getTypeArguments().get(0), state)),
Stream.of(cmpType.tsym.getSimpleName()).filter(u -> methodNameIsComparing))
.collect(joining(","));
return String.format("<%s>%s", typeArgument, preferredMethodName);
9f7ddfa
to
2ef98c3
Compare
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.
Rebased and added one more commit. Suggested commit message:
Have `PrimitiveComparisonCheck` retain relevant generic type parameters (#39)
private static Optional<Fix> tryFix( | ||
MethodInvocationTree tree, VisitorState state, Type cmpType, boolean isStatic) { | ||
private static Optional<Fix> tryMakeMethodCallMorePrecise( |
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'm not sure what it means to make a method call "more precise". IMHO the old name was fine, but how about attemptMethodInvocationReplacement
?
(That said, tryFix
is also used in other checks.)
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 like attemptMethodInvocationReplacement
. I can see why tryFix
in the context of a specific check could make sense, but I feel that (e.g.) the name attemptMethodInvocationReplacement
makes it clearer than the original name.
.map(preferredMethodName -> suggestFix(tree, preferredMethodName, state)); | ||
} | ||
|
||
private static String getPreferredMethod(VisitorState state, Type cmpType, boolean isStatic) { | ||
private static String mayPrefixWithTypeArguments( |
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'd expect a method named mayX
to return a boolean
. How about e.g. prefixTypeArgumentsIfRelevant
?
private static String getPreferredMethod(VisitorState state, Type cmpType, boolean isStatic) { | ||
private static String mayPrefixWithTypeArguments( | ||
String preferredMethodName, MethodInvocationTree tree, Type cmpType, VisitorState state) { | ||
int typeArgumentsCount = tree.getTypeArguments().size(); |
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.
In English "count" is preceded by the singular of whatever is counted.
int typeArgumentsCount = tree.getTypeArguments().size(); | |
int typeArgumentCount = tree.getTypeArguments().size(); |
Stream.concat( | ||
Stream.of(Util.treeToString(tree.getTypeArguments().get(0), state)), | ||
Stream.of(cmpType.tsym.getSimpleName()).filter(u -> methodNameIsComparing)) | ||
.collect(joining(",")); |
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.
.collect(joining(",")); | |
.collect(joining(", ")); |
That said, we can drop the String.format
below if here we do
.collect(joining(",")); | |
.collect(joining(", ", "<", ">")); |
int typeArgumentsCount = tree.getTypeArguments().size(); | ||
boolean methodNameIsComparing = "comparing".equals(preferredMethodName); | ||
|
||
if (typeArgumentsCount == 0 || (typeArgumentsCount == 1 && !methodNameIsComparing)) { |
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 tests also pass if I simplify this to:
if (typeArgumentsCount == 0 || (typeArgumentsCount == 1 && !methodNameIsComparing)) { | |
if (typeArgumentsCount == 0) { |
I think we should add additional tests to demonstrate in which case the added complexity is necessary. IIUC the check can then become:
if (typeArgumentsCount == 0 || (typeArgumentsCount == 1 && !methodNameIsComparing)) { | |
if (tree.getTypeArguments().isEmpty() || preferredMethodName.startsWith("then")) { |
" Comparator<A> bCmp = Comparator.<A>comparingInt(o -> (byte) 0);", | ||
" Comparator<A> cCmp = Comparator.<A>comparingInt(o -> (char) 0);", | ||
" Comparator<A> sCmp = Comparator.<A>comparingInt(o -> (short) 0);", | ||
" Comparator<A> iCmp = Comparator.<A>comparingInt(o -> 0);", | ||
" Comparator<A> lCmp = Comparator.<A>comparingLong(o -> 0L);", | ||
" Comparator<A> fCmp = Comparator.<A>comparingDouble(o -> 0.0f);", | ||
" Comparator<A> dCmp = Comparator.<A>comparingDouble(o -> 0.0);", |
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 should also test the cases where (in a non-static import context) absent type information stays absent.
@@ -37,7 +37,6 @@ | |||
*/ | |||
// XXX: Add more documentation. Explain how this is useful in the face of refactoring to more | |||
// specific types. | |||
// XXX: Change this checker's name? |
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.
ComparatorUsage
and CanonicalComparatorUsage
are nice, but hint at something more generic. Let's keep the current name, at least in the context of the current PR.
2ef98c3
to
c873787
Compare
Rebased. Changes look good! |
No description provided.