Issue #13167: Fix NPE in UnusedLocalVariable check#13543
Issue #13167: Fix NPE in UnusedLocalVariable check#13543romani merged 1 commit intocheckstyle:masterfrom
Conversation
| boolean result = false; | ||
| DetailAST parentAst = ast.getParent(); | ||
| while (parentAst != null) { | ||
| if (TokenUtil.isOfType(parentAst, CONTAINERS_FOR_ANON_INNERS) |
There was a problem hiding this comment.
Please rename this collection to something like CLASS_BODY_DECLARATION_TOKENS or even ANONYMOUS_INNER_CLASS_SCOPES in a separate commit first, container is nonsense in this context. Then update the method naming, etc. appropriately.
...s/checkstyle/checks/coding/unusedlocalvariable/InputUnusedLocalVariableLambdaExpression.java
Show resolved
Hide resolved
nrmancuso
left a comment
There was a problem hiding this comment.
Another item as you push changes for collection:
| * Whether the ast is nested under tokens of type | ||
| * {@link UnusedLocalVariableCheck#CONTAINERS_FOR_ANON_INNERS} or {@link TokenTypes#LAMBDA}. |
There was a problem hiding this comment.
Please remove mentions of specific tokens, such a list is bound to get outdated/ignored, and is an implementation detail that the caller should not have to worry about.
| * @return {@code true} if ast is nested under tokens of type | ||
| * {@link UnusedLocalVariableCheck#CONTAINERS_FOR_ANON_INNERS} | ||
| * or {@link TokenTypes#LAMBDA} |
32e6955 to
f92e369
Compare
f92e369 to
64e6248
Compare
| if (currentAst.getType() == TokenTypes.LAMBDA) { | ||
| topMostLambdaAst = currentAst; |
There was a problem hiding this comment.
This is a time-complexity mutation. The reason I have added this to the suppressions list is because removing this condition will make the entire COMPILATION_UNIT to be processed again. And having many nested lambdas can make the entire COMPILATION_UNIT be processed multiple times.
If the penalty was small, I would have inclined towards pitest, but processing the entire COMPILATION_UNIT multiple times isn't a wise option IMO.
|
Regression for this PR: https://rveach.no-ip.org/checkstyle/regression/345/ 1 NPE is removed, no other changes. |
64e6248 to
a5057f3
Compare
|
As discussed, analysis is right at #13543 (comment) . This would be a very complex check, which I am unfamilar with, to fix pitest. If we are good, I can write a reasoning for the suppression and create a new issue to resolve pitest suppressions. Maybe it can be done as part of the GSoC project. |
9e050eb to
c2a3217
Compare
|
It seems to me this check has a check inside itself. We have the first set of visits which is collecting information, then we have a custom tree walker with its own visits using the information collected from the first. It is not re-walking the entire tree in both times, but this is what makes this check complex by itself. The mutation is in the first "check", and its usage is being done in the 2nd. Violations are picked and logged by exact ASTs, and we hide duplicate same violations, so I don't believe this can be killed, from what I am seeing so far. I can confirm this on my local by printing all violations and ignoring duplicates. Running on These mutations may be a complex form of a time saver. |
|
Yeah, I remember some of these mutations to be like that. One mutation was particularly like processing the whole
Yeah, it does that. The reason for two traversals is that a class may be defined further down the AST but may be used before, so scoping, etc., becomes difficult in that scenario, particularly with anon inner classes. |
Do you have any real examples with many nested lambdas? I'm interested in whether this is a genuine concern or just something we think is problematic when, in practice, it isn't.
What's the penalty? Do you have some numbers at hand? |
I don't know if there is some pattern using nested lambdas. It is not a rare case, that I'm sure.
Penalty is directly proportional to the number of nodes in the ast. It will traverse the entire ast again (maybe multiple times too). |
|
I didn't find a quick and clear way to test Checkstyle performance for the fix with/without optimisation, so I ended up running both versions against the following list of projects via regression diff report: For this check's config: I thought if we had a performance problem, the unoptimised fix would give x-times higher processing time. Here are the actual numbers (I ran the regression diff report 3 times for each build and choose the median): There is no difference. I suggest we remove optimisation and use a simplified fix that avoids two |
|
I would love to have no pitest suppression, rather than nano optimization. In long run no pitest will be more beneficial. |
|
@nrmancuso , @rnveach , please share your opinion. |
|
I am ok for this PR as it is now or closing it. I don't agree with applying the pitest mutations to the code since that would degrade this check more than it is. We should already look into the issue that it is reporting the same token 2x already. |
My opinion is that we have already spent too much effort on this pitest suppression, let’s either merge or close this. I think it is personally ridiculous to traverse the entire AST up to the root node when we know that we can (and should) stop when we reach the enclosing anonymous class. We are humans that can think and reason, not robots that only deal in pitest logic. |
c2a3217 to
4861a81
Compare
|
All suppression(pitest + spotbugs) in this PR smells badly. |
romani
left a comment
There was a problem hiding this comment.
Ok to merge.
We will improve in separate PR
Resolves #13167