-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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 #11087: New check ChainedMethodCallWrap #11231
Issue #11087: New check ChainedMethodCallWrap #11231
Conversation
final boolean isArrayTypeDeclarationStart = nextSibling != null | ||
&& (nextSibling.getType() == TokenTypes.ARRAY_DECLARATOR | ||
|| nextSibling.getType() == TokenTypes.ANNOTATIONS) | ||
&& isArrayTypeDeclaration(nextSibling); | ||
final boolean isArrayTypeDeclarationStart = isArrayTypeDeclarationStart(nextSibling); |
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.
Extracted to reduce cognitive complexity.
Truth.assertWithMessage("test").that(1).isNotEqualTo(2); | ||
// ^---- ok, specified pattern is different |
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.
Though the method being implied is the same, the check matches again the complete method chain, can be changed if asked for but then it will also match for-
SomeOtherBuilder.assertWithMessage().that.....
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.
Please add this to documentation example
5f1ade3
to
e279be6
Compare
558ff1b
to
793cde2
Compare
Github, generate report |
01b6534
to
ce667a2
Compare
Github, generate report |
ce667a2
to
b6d4f18
Compare
b6d4f18
to
00cdd7b
Compare
Github, generate report |
00cdd7b
to
7cd43c9
Compare
Github, generate report |
<module name="ChainedMethodCallWrap">
<property name="id" value="streamMethodCalls"/>
<property name="identifierPattern" value=".*\.(s|S)tream.*"/>
</module> <module name="ChainedMethodCallWrap">
<property name="id" value="optionalMethodCalls"/>
<property name="identifierPattern" value=".*\.(o|O)ptional.*"/>
</module> <module name="ChainedMethodCallWrap">
<property name="id" value="streamMethodCalls"/>
<property name="identifierPattern" value=".*\.(s|S)tream.*"/>
<property name="maxCallsInSingleLine" value="2" />
</module <module name="ChainedMethodCallWrap">
<property name="id" value="optionalMethodCalls"/>
<property name="identifierPattern" value=".*\.(o|O)ptional.*"/>
<property name="maxCallsInSingleLine" value="2" />
</module> For stream method calls, I would prefer 3. |
Github, generate report |
optionalMethodCallsAllProjects: |
The optional pattern isn't that useful, stream one still has good usecase |
Ma is 2 in config, but 1 in message. I have worries on Did we consider in design wrapping demands for method that use lambda or method ref? |
Github, generate site |
That violation is for method calls wrapped on multiple lines, that violation is basically: foo.stream()
.abc().abc() // violation, Wrap chained method call, max allowed on a line is 1.
.abc(); In config, we have set |
9e321d3
to
e30a481
Compare
@Vyom-Yadav , please rebase, let's review it one more time |
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.
As I mentioned above, if Check is not general we need extend its name with some words to mention this. What identifier is used? Can configure it for stream()
(most jdk collections) ? I see diff report on it, can we apply it to our config to be enforced from the beginning.
If we have no energy to continue, I recommend to move it to https://github.com/sevntu-checkstyle/sevntu.checkstyle/tree/master/sevntu-checks as is, no extra changes will be required no questions asked.
https://checkstyle-diff-reports.s3.us-east-2.amazonaws.com/9e321d3_2023172051/reports/diff/checkstyle/index.html#A10 this looks like false positive, after stream there is no chained call on same line.
Please rebase.
Items:
config/checkstyle-checks.xml
Outdated
@@ -134,7 +134,7 @@ | |||
</module> | |||
<module name="RegexpSingleline"> | |||
<property name="id" value="assertThatShouldBeOnSeparateLine"/> | |||
<property name="format" value="assertWithMessage\(.*\).that\("/> | |||
<property name="format" value="^[^*]*assertWithMessage\(.*\).that\("/> |
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 new Check is powerful, why we need this assertThatShouldBeOnSeparateLine now ?
It was good hack without special Check. But if we have special Check, we do not need this instance.
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 isn't required anymore, removed. The check can handle it.
<module name="ChainedMethodCallWrap">
<property name="identifierPattern" value="^assert.*"/>
<property name="maxCallsInSingleLine" value="2" />
</module>
@@ -910,6 +910,10 @@ | |||
<module name="TypecastParenPad"/> | |||
<module name="WhitespaceAfter"/> | |||
<module name="WhitespaceAround"/> | |||
<module name="ChainedMethodCallWrap"> | |||
<property name="identifierPattern" value="^assert.*"/> | |||
<property name="maxCallsInSingleLine" value="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.
We need to eat food we produce, if we claim that Check is general, let's apply it to other chained code.
If we can not apply it to our codebase, nobody will apply, we do not need unused 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.
Sure, do you have any method chains in mind you don't want to be changed?
* @param dotAst ast node of type {@link TokenTypes#DOT} | ||
*/ | ||
private static void extractFullIdentFromDotAst(FullIdent full, DetailAST dotAst) { | ||
DetailAST firstChildToExtract = dotAst.getFirstChild(); |
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 need to avoid extra implementations in API package.
Is there a way to hide such implementation in Check or some Utility 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.
Yes, this would be required too. All discussion at #11672 and surrounding issues indicate that changing FullIdent will break some classes even if the implementation of FullIdent is correct (which is this one; the master codebase is buggy).
I would also deprecate the usage of FullIdent as it is buggy, and fixing it would require fixing VariableDeclarationDistanceUsage.
Either VariableDeclarationDistanceUsage
should have a separate implementation for FullIdent (the current buggy one), which will allow us to fix the main one. What do you suggest?
assertWithMessage("test").that(1).isEqualTo(1); | ||
// violation above '3 method calls on single line, max allowed is 2' | ||
assertWithMessage("test") | ||
.that(1).isNotEqualTo(2); // ok |
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.
Please remove //ok
we can keep ok comments with details only (extra text)
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.
Done.
src/xdocs/config_whitespace.xml
Outdated
<tr> | ||
<td>identifierPattern</td> | ||
<td> | ||
Specify method calls to be checked. By default, identifierPattern matches |
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 have problems to understand what is identifier
https://checkstyle.org/property_types.html we need some explanation in this Check on this term.
In examples I see that class name can be used, but it conflicts with Specify method calls
.
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 identifier comprises of the actual words in the chained method call. It comprises of method name, the object on which the method is invoked, the constructor in between. Example:
new Pizza.Builder().build();
, here the methodIdentifier
we obtain is Pizza.Builder.build
@romani No, it is not, the identifierPattern is I see where you are coming from, you want to ignore all calls before The current design does not allow you to ignore certain method calls before or after a method call, that can be added is an enhancement later on. |
e30a481
to
97e5ad7
Compare
97e5ad7
to
e1b7e12
Compare
I will fix CI errors after we come to some conclusions on various aspects. |
I just try to understand how it works, and I am failing, so it means that nobody will understand it, so nobody will use it.
in my mind code is good, I do not see a reason to change it. May be we should make regexp end position as definition from where to demand wrapping? So it will be like "wrap after stream()" that is how most people are doing wrapping of chained.
that is my point, lets move it to senvtu project and start to use and in real practice see what changes in design are required. |
Alright, let's move it to sevntu and iterate over there. What do you want to do about |
Just copy required code as you need and code for full ident too. |
@Vyom-Yadav let's close this PR, code and comments here will stay forever in Github, and we can come back and move it to sevntu at any time. |
Resolves #11087: New check chained method call wrap
Diff Regression config: https://gist.githubusercontent.com/Vyom-Yadav/98dceb63a79f4833e85fff9b2e1464a6/raw/e5d475dd0a62d241e4aa20e58f607672133859fb/my_checks.xml
Diff Regression patch config: https://gist.githubusercontent.com/Vyom-Yadav/273327b9c6cd6963b7dade792bc2c9c2/raw/722734822d2766fded891ddf25819194ba6cdedf/patch_config.xml
Report label: optionalMethodCallsAllProjects
Default config of check:
Config used by checkstyle internally:
Report for the following config (Match all method calls, report is huge, was used to check for exceptions):
https://checkstyle-diff-reports.s3.us-east-2.amazonaws.com/3d90a1c_2023113432/reports/diff/index.html
Report for the config used by checkstyle:
https://checkstyle-diff-reports.s3.us-east-2.amazonaws.com/793d000_2023080701/reports/diff/index.html
Report for FullIdent:
Checkstyle Checks:
False Negative: VariableDeclarationUsageDistance #11335)
https://vyom-yadav.github.io/DiffReport/diff-full-ident-main/index.html
Sevntu Checks: https://vyom-yadav.github.io/DiffReport/diff-full-ident-sevntu/index.html
Site: https://checkstyle-diff-reports.s3.us-east-2.amazonaws.com/793d000_2023110050/config_whitespace.html#ChainedMethodCallWrap
contribution PR: checkstyle/contribution#774
Some thoughts about the default configuration and check rationale: #11231 (comment)