-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Issue #11374: Fix false positive related to anon inner classes in UnusedLocalVariableCheck #15969
Conversation
Github, generate report for UnusedLocalVariable/all-examples-in-one |
Extra Test coverage is required
|
Report for UnusedLocalVariable/all-examples-in-one: |
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.
Items
src/main/java/com/puppycrawl/tools/checkstyle/utils/CheckUtil.java
Outdated
Show resolved
Hide resolved
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.
From requirethis config https://github.com/checkstyle/checkstyle/actions/runs/12128897260/job/33816256524?pr=15969
org.pitest:pitest-maven:1.17.2:mutationCoverage (default-cli) on project checkstyle: Mutation score of 99 is below threshold of 100
One more coverage problem:
<description>replaced call to java/lang/Math::min with argument</description>
+ <lineContent>.min(typeDeclarationToBeMatchedLength, patternTypeDeclaration.length());</
Items
src/main/java/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java
Outdated
Show resolved
Hide resolved
@kkoutsilis, do you need any help with CI problems? |
Hey @romani, I didn't have time to mess around with it, will set some time aside this weekend and if I need help I'll let you know, thanks🙂 |
7c213d4
to
9ffee19
Compare
Rebased in web UI to let ci pass. |
Github, generate report for UnusedLocalVariable/all-examples-in-one |
I don't think I killed the mutations yet, but working on it |
Report for UnusedLocalVariable/all-examples-in-one: |
Should be good now, let's see if the CI agrees |
Github, generate report for UnusedLocalVariable/all-examples-in-one |
@Vyom-Yadav, please glance if you still around. |
Report for UnusedLocalVariable/all-examples-in-one: |
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.
only minor comments:
.../checkstyle/checks/coding/unusedlocalvariable/InputUnusedLocalVariableAnonInnerClasses2.java
Outdated
Show resolved
Hide resolved
src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/UnusedLocalVariableCheck.java
Outdated
Show resolved
Hide resolved
src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/UnusedLocalVariableCheck.java
Show resolved
Hide resolved
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.
Ok to merge
I'll take a look on the weekend. |
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.
Items:
* @param matchingQualifiedName type declaration to be matched | ||
* @return the type declaration matching count | ||
*/ | ||
private static int getAnonSuperTypeMatchingCount(String patternQualifiedName, |
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.
It is not clear to me why this method name has to be so lengthy, and why it should care about anon/super/type/etc. It takes two string values that represent two qualified names, and returns the count of characters that match between the two, right? private static int countMatchingQualifierChars(String pattern, String candidate)
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.
AnonSuper
imply that usage of it not general or at least we don't want to think if it could be general.
Naming "count......" Is good.
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.
Why can’t it be general? This is my point.
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 have no goal to make it general now, if someone wants, he can improve it to be general in separate PR, but current implementation is limited.
@@ -647,20 +647,60 @@ private static TypeDeclDesc getTheNearestClass(String outerTypeDeclName, | |||
* @param secondTypeDecl second input type declaration | |||
* @return difference between type declaration name matching count | |||
*/ | |||
private static int getTypeDeclarationNameMatchingCountDiff(String outerTypeDeclName, | |||
private static int getAnonTypeDeclarationNameMatchingCountDiff(String outerTypeDeclName, |
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.
Similar to above, we are exposing implementation details in the method name, and it doesn't really help us to understand what this method does at a conceptual level or why we care about it. Additionally, using diff
and match
in the name is misleading; once we are comparing depths, we really aren't talking about a "diff" any longer.
Please make this method signature to be private static int calculateTypeDeclarationDistance(String outerTypeName, TypeDeclDesc firstType, TypeDeclDesc secondType)
.
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.
If we name it a bit more general, could it be problem of misusage? Non of arguments imply that implementation is designed for annon type only for now.
If someone wants to make general method, he can create with general name and do appreciate implementation.
Just think on this one more time, this had concerns with names even in original PR.
I don't want to let this PR stuck again.
If you really see it should be changed , just confirm one more time, and we will do 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 existing name tells me everything except for what this method actually does 😂
private static int getAnonTypeDeclarationNameMatchingCountDiff(String outerTypeDeclName, | ||
TypeDeclDesc firstTypeDecl, | ||
TypeDeclDesc secondTypeDecl) { | ||
int diff = Integer.compare( | ||
CheckUtil.typeDeclarationNameMatchingCount( | ||
getAnonSuperTypeMatchingCount( | ||
outerTypeDeclName, secondTypeDecl.getQualifiedName()), | ||
CheckUtil.typeDeclarationNameMatchingCount( | ||
getAnonSuperTypeMatchingCount( | ||
outerTypeDeclName, firstTypeDecl.getQualifiedName())); | ||
if (diff == 0) { | ||
diff = Integer.compare(firstTypeDecl.getDepth(), secondTypeDecl.getDepth()); | ||
} | ||
return diff; | ||
} |
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.
While we are here, we can also refactor this method a bit to use immutable data and make what we are doing more clear:
final int firstMatchCount = countMatchingQualifierChars(outerTypeName, firstType.getQualifiedName());
final int secondMatchCount = countMatchingQualifierChars(outerTypeName, secondType.getQualifiedName());
final int matchDistance = Integer.compare(secondMatchCount, firstMatchCount);
final int distance;
if (matchDistance == 0) {
distance = Integer.compare( firstType.getDepth(), secondType.getDepth());
} else {
distance = matchDistance;
}
return distance;
final int typeDeclarationToBeMatchedLength = matchingQualifiedName.length(); | ||
final int minLength = Math | ||
.min(typeDeclarationToBeMatchedLength, patternQualifiedName.length()); | ||
final boolean shouldCountBeUpdatedAtLastCharacter = |
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.
Why do we care about this? This code is not obvious to me.
@@ -631,10 +631,10 @@ private boolean hasSameNameAsSuperClass(String superClassName, TypeDeclDesc type | |||
* @param typeDeclWithSameName typeDeclarations which have the same name as the super class | |||
* @return the nearest class | |||
*/ | |||
private static TypeDeclDesc getTheNearestClass(String outerTypeDeclName, | |||
private static TypeDeclDesc getTheNearestClassOfAnonInnerClass(String outerTypeDeclName, |
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.
Shouldn’t this be getClosestMatchingTypeDeclaration
?
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 naming inconsistencies in this check really make this code difficult to understand: the type we use for nearly all the heavy lifting is called TypeDeclDesc
, but we nearly always name the variables with class
.
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.
getClosestMatchingTypeDeclaration
Ok, Do you fully dislike OfAnonInner
clarification in 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.
I don’t know why it matters.
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.
It is very specific method with very specific implementation
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.
It is very specific method with very specific implementation
Leaking implementation details into the method name is also a red flag.
Are we "getting the nearest class of anonymous inner class"? What does this even mean? What is a nearest class "of" another class? Why is this method not returning a class, if we are getting a class?
Or, are we "getting the closest matching type declaration", since the method returns a type declaration description?
I've left my review, @romani do with it what you will |
@kkoutsilis , please apply suggestions from @nrmancuso. |
Hey @romani, will look into it hopefully this weekend |
…ses in UnusedLocalVariableCheck
Hey @romani, I believe I renamed all the methods as @nrmancuso suggested. Sorry for any inconvenience this PR has caused. If there are further changes required please let me know and I will try to apply as soon as I can. I have limited time for the next week or so. |
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.
Good stuff @kkoutsilis, thanks a lot for your contribution
Aims to close #11374
Based on abandoned #12795