Skip to content
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

[java] Ignore unused declarations that have special name #2957

Closed
linusjf opened this issue Dec 2, 2020 · 29 comments · Fixed by #3066
Closed

[java] Ignore unused declarations that have special name #2957

linusjf opened this issue Dec 2, 2020 · 29 comments · Fixed by #3066
Assignees
Labels
an:enhancement An improvement on existing features / rules
Milestone

Comments

@linusjf
Copy link

linusjf commented Dec 2, 2020

Implemented solution via #3066:

The following rules are affected:

The following variable names are ignored:

  • any name starting with ignored, e.g. ignoredParameter
  • any name starting with unused, e.g. unusedVar

Is your feature request related to a problem? Please describe.
UnusedLocalVariable, UnusedFormalParameter flag all unused variables.

Describe the solution you'd like
Please add a property to the rule specifying a pattern such as starts with $, _ or unused for the variable name so that variables that meet the criteria are excluded. Additionally, you could support custom annotations that mark the variables as Unused. e.g., @Unused or @Ignored.
E.g., https://github.com/Lanchon/r8/blob/e22a77d26e30615bfc9b5f598bb0f58f10dd082c/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAnnotationTestClasses.java

Describe alternatives you've considered
Example code flagged by ForLoopCanBeForEach when usual for loop used:

@SuppressWarnings("PMD.UnusedLocalVariable")
  @Override
  public Solution solve() {
    int[] dp = new int[capacity + 1];

    List<Item> itemsList = new ArrayList<>(items.length);
    int i = 0;
    for (int dpVal : dp) {
      for (Item item : items) {
        if (item.weight <= i) {
          int includedVal = dp[i - item.weight] + item.value;
          if (includedVal > dp[i]) dp[i] = includedVal;
        }
      }
      ++i;
    }
    path(items, capacity, dp, itemsList);
    itemsList = Item.pack(itemsList);
    return new Solution(itemsList, dp[capacity]);
  }

Additional context
Haskell/Python style
Error-prone

Also see #2923

Referenced from: #2838

@linusjf linusjf added the an:enhancement An improvement on existing features / rules label Dec 2, 2020
@linusjf linusjf closed this as completed Dec 2, 2020
@linusjf linusjf reopened this Dec 2, 2020
@linusjf linusjf changed the title [java] Annotate unused X either with special variable name or special annotation [java] Annotate unused X either with special name or annotation Dec 3, 2020
@linusjf
Copy link
Author

linusjf commented Dec 4, 2020

2958 adds to this by resolving the main method conundrum where args could be whitelisted. Worth updating...

Thanks to @marquiswang

@rsoesemann rsoesemann added this to the 6.30.0 milestone Dec 8, 2020
@oowekyala
Copy link
Member

I still don't think making this a property would buy us anything useful. It could be inconsistent between rules, and is encouraging projects making up their own conventions, like your dollar prefix. @SuppressWarnings("unused") and ignored/unused prefixes are supported by many other tools and I don't see a reason why they're not enough anymore.

@linusjf
Copy link
Author

linusjf commented Dec 8, 2020

@oowekyala Project conventions are exactly that---project conventions. It would provide them flexibility. Yes, there's potential for misuse but surely nobody's going to fill that property field with numerous variable names. The other option, as I pointed out, is to make an exception for the main method parameters, when unused, via an additional property. That's more correct.

@linusjf
Copy link
Author

linusjf commented Dec 8, 2020

I still don't think making this a property would buy us anything useful. It could be inconsistent between rules, and is encouraging projects making up their own conventions, like your dollar prefix.

_ as a prefix is a valid choice.

@linusjf
Copy link
Author

linusjf commented Dec 8, 2020

I still don't think making this a property would buy us anything useful. It could be inconsistent between rules, and is encouraging projects making up their own conventions, like your dollar prefix.

_ as a prefix is a valid choice.

It also avoids lengthening the variable name. _xcc or $xcc is preferable to unusedXcc or ignoredXcc.

@linusjf
Copy link
Author

linusjf commented Dec 8, 2020

and I don't see a reason why they're not enough anymore.

Standardisation is all very fine but I'd rather aim for 'user delight' than 'user satisfaction'.

@oowekyala
Copy link
Member

I don't think there's any delight in adding a configuration property that needs to be synchronized between more than 3 rules to be consistent.

The root problem is possibly that we have several rules that basically check variants of the same thing (UnusedFormalParameter, UnusedPrivateField, UnusedLocalVariable). Merging them could make this mostly go away (eg, into a single UnusedDeclaration rule), and adding a property could make sense. But we don't need that to implement the first part (make them all uniformly recognise unused/ignored).

@linusjf
Copy link
Author

linusjf commented Dec 10, 2020

But we don't need that to implement the first part (make them all uniformly recognise unused/ignored).

This part has to be implemented with _ as a prefix an integral component. How this interacts with naming conventions is irrelevant. It is only one of the ways to mark unused xxxx.

I like the idea about merging all the rules together. That and the rest can be implemented in a later release (7.0.0?).

@linusjf linusjf changed the title [java] Annotate unused X either with special name or annotation [java] Annotate unused declaration either with special name or annotation Dec 10, 2020
@oowekyala
Copy link
Member

This part has to be implemented with _ as a prefix an integral component.

It doesn't. This is a rarer convention (which I've in fact only ever seen in other languages), and some projects may use the _ prefix for something else. I think this should be an opt-in. It can remain unavailable until we add a property.

To sum it up, we will:

I'm still against supporting custom suppression annotations. The example you linked is obviously not real-world code, and the point of @scala.unused is that it interacts with the Scala compiler, the only equivalent Java being @SuppressWarnings("unused"). Please don't insist, or do it in another issue, because just like in #2838, that is another thread of discussion.

Also I'm not sure why @rsoesemann you scheduled it for 6.30.0, are you working on it?

@linusjf
Copy link
Author

linusjf commented Dec 10, 2020

This part has to be implemented with _ as a prefix an integral component.

It doesn't. This is a rarer convention (which I've in fact only ever seen in other languages), and some projects may use the _ prefix for something else. I think this should be an opt-in. It can remain unavailable until we add a property.

Whether projects assign significance to the _ prefix is irrelevant to these rules. How is it relevant? And I am not all happy with having these values hard-coded within PMD. I'd rather have them in a property (startsWith) at the outset.

@linusjf
Copy link
Author

linusjf commented Dec 10, 2020

This part has to be implemented with _ as a prefix an integral component.

It can remain unavailable until we add a property.

I'm with you on this. But only for the reason that you don't wish to give your users something and then take it away. This, however, can be mitigated by defaulting this value in the property to be added.

@linusjf

This comment has been minimized.

@rsoesemann

This comment has been minimized.

@linusjf

This comment has been minimized.

@oowekyala oowekyala removed this from the 6.30.0 milestone Dec 11, 2020
@linusjf

This comment has been minimized.

@oowekyala

This comment has been minimized.

@linusjf

This comment has been minimized.

@linusjf

This comment has been minimized.

@adangel
Copy link
Member

adangel commented Dec 12, 2020

Sorry for chiming in a bit late, but two comments from my side:

  • Using/establishing _ (underscore) as a marker for unused (local) variables/formal parameters etc. should not be done without much, much thought: _ is a reserved keyword in Java -> https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.9 , so you anyway can't name your variable/parameter as underscore, as it won't compile. One possible future use of this "keyword" is http://openjdk.java.net/jeps/302 . So, it might be, that at some point, _ is indeed the convention/rule for marking such things as unused. But then it would not be us to establish the convention but rather the Java language itself and it would be "built-in".

  • Your example in the original post does not make sense. The rule correctly says that dpVal is not used, because it is not used indeed. Why would you write this code with a for-each loop? Why not using a normal for loop? As you anyway need the index variable i. From my point of view, this variable is unused and there is no problem with the rule "UnusedLocalVariable". Having said that, it might be there are valid cases (especially for formal parameters), but we don't have examples for this. So I consider the entire discussion more theoretical than real use case driven.

As you mention, that the original example was driven by ForLoopCanBeForEach loop - maybe you are more talking about a false-positive of ForLoopCanBeForEachLoop rather than UnusedLocalVariable?

@linusjf
Copy link
Author

linusjf commented Dec 12, 2020

  • Using/establishing _ (underscore) as a marker for unused (local) variables/formal parameters etc. should not be done without much, much thought: _ is a reserved keyword in Java -> https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.9 , so you anyway can't name your variable/parameter as underscore, as it won't compile. One possible future use of this "keyword" is http://openjdk.java.net/jeps/302 . So, it might be, that at some point, _ is indeed the convention/rule for marking such things as unused. But then it would not be us to establish the convention but rather the Java language itself and it would be "built-in".

How does naming a variable, method or parameter starting with _ break any conventions? I don't see why we need to use over-verbose names like unusedArgs or ignoredArgs. It jars.

  • Your example in the original post does not make sense. The rule correctly says that dpVal is not used, because it is not used indeed. Why would you write this code with a for-each loop? Why not using a normal for loop? As you anyway need the index variable i. From my point of view, this variable is unused and there is no problem with the rule "UnusedLocalVariable". Having said that, it might be there are valid cases (especially for formal parameters), but we don't have examples for this. So I consider the entire discussion more theoretical than real use case driven.

This is not a false-positive example. It's a case where the rule applies and should be mitigated by the measures suggested by the rule. As is done by SuppressWarnings... above.

As you mention, that the original example was driven by ForLoopCanBeForEach loop - maybe you are more talking about a false-positive of ForLoopCanBeForEachLoop rather than UnusedLocalVariable?

Yep.

@oowekyala
Copy link
Member

oowekyala commented Dec 12, 2020

Having said that, it might be there are valid cases (especially for formal parameters), but we don't have examples for this. So I consider the entire discussion more theoretical than real use case driven.

I don't think this is theoretical at all.

For example, resources:

Those are by the way false negatives of UnusedLocalVariable. They should be reported, unless, like here, they are meant to be unused (and this should be obvious in their name, which here it isn't).

Another example is when you have a method which is used by a method reference, and so must have the same formals as the functional interface. Recently I wrote a bunch of those, the unused parameters are there for future use if need be, and it's ok to just suppress the violation. Suppressing by naming is more lightweight than annotations.

Also I think it's normal to allow suppression via name, when EmptyCatchBlock and UnusedAssignment already do support this. This makes even more sense if we merge some of the rules together. Also, the Intellij and error prone checks support this.

--

How does naming a variable, method or parameter starting with _ break any conventions? I don't see why we need to use over-verbose names like unusedArgs or ignoredArgs. It jars.

I think there's a misunderstanding: @adangel is talking about having the identifier just _, @Fernal73 is talking about having an underscore as a prefix, eg _myvar. The latter is mostly what I was talking about too.

@linusjf
Copy link
Author

linusjf commented Dec 12, 2020

Suppressing by naming is more lightweight than annotations.

You mean we should use SuppressWarnings("RuleName") , SuppressWarnings("unused") or rename the variable as outlined in the rule documentation. (SuppressWarnings("all") will not retain semantics.)

An annotation is elegant but there is an overhead to it.

@oowekyala
Copy link
Member

I mean suppressing by renaming the variable, specifically as opposed to using an annotation or comment

@linusjf
Copy link
Author

linusjf commented Dec 12, 2020

@oowekyala In terms of readability and style, annotations are better.

@oowekyala
Copy link
Member

So what? You admit yourself there is an overhead. You cannot just take both sides of the argument for the sake of contradiction. And my point is that those naming conventions (prefix a variable with "unused") are already considered acceptable by other tools, and by some of our rules (eg, EmptyCatchBlock).

@linusjf
Copy link
Author

linusjf commented Dec 12, 2020 via email

@linusjf
Copy link
Author

linusjf commented Dec 13, 2020

If you're concerned about 'polluting' the code with annotations, then renaming the variable/method/parameter or suppressing it via regex/Xpath may be the best solution. I doubt, however, that @SuppressWarnings can be avoided altogether for any large code base.

@linusjf
Copy link
Author

linusjf commented Dec 13, 2020

If you're concerned about 'polluting' the code with annotations, then renaming the variable/method/parameter or suppressing it via regex/Xpath may be the best solution. I doubt, however, that @SuppressWarnings can be avoided altogether for any large code base.

Xpath suppressions can mitigate the main conundrum by allowing the user to suppress the rule for the method.

@linusjf
Copy link
Author

linusjf commented Dec 13, 2020

If you're concerned about 'polluting' the code with annotations, then renaming the variable/method/parameter or suppressing it via regex/Xpath may be the best solution. I doubt, however, that @SuppressWarnings can be avoided altogether for any large code base.

Xpath suppressions can mitigate the main conundrum by allowing the user to suppress the rule for the method.

This won't work well with a merged rule since I'd only like to suppress UnusedFormalParameter unless there's plans to specify interactions with sub-components or sub-rules or other properties.

@oowekyala oowekyala added this to the 6.31.0 milestone Jan 8, 2021
@oowekyala oowekyala self-assigned this Jan 8, 2021
@adangel adangel changed the title [java] Annotate unused declaration either with special name or annotation [java] Ignore unused declarations that have special name Jan 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
an:enhancement An improvement on existing features / rules
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants