PMD: How to ignore short variable names in lambda expressions only

Viewed 752

I'm looking for a solution that allows me to check short variable names with PMD, while excluding lambdas from this rule.

Mainly, the reason for this is that IntelliJ auto-names common lamba variables with single characters, esp. java.lang.Strings that are always abbreviated like

aListFullOfStrings.forEach(s -> s.replaceAll(" ", ""));

I prefer that abbreviation but I don't want to add suppressions to all my lambdas. I couldn't find any way to adjust my PMD rules in order to solve this gracefully.

Suggestions are much appreciated - I'm not that experienced with all their configurations.

3 Answers

You can leverage the xpath based suppression capabilities of PMD.

On your ruleset XML, simply configure the property for this particular rule as so:

<rule ref="rulesets/java/naming.xml/ShortMethodName">
  <properties>
    <property name="violationSuppressXPath" value=".[ancestor::LambdaExpression]"/>
  </properties>
</rule>

Non the less, as a PMD maintainer, I believe this is a legitimate case for altering the rule on PMD itself, so I've added github.com/pmd/pmd/issues/720 to track this.

By default PMD will flag variables with names of less than 3 characters, although it already exempts some legitimate cases such as for-loop variables. You need to tweak PMD so that it also exempts variables within lambda expressions.

That's done by amending one of PMD's many ruleset files named naming.xml which resides within the jar file {pmd installation dir}\lib\pmd-java-5.8.1.jar (if you are using the latest release of PMD). One approach is as follows:

  • Extract the contents of the jar file pmd-java-5.8.1.jar to some temporary folder.

  • Edit the extracted file naming.xml and locate the text rule name="ShortVariable" then insert the text [not(ancestor::LambdaExpression)] as shown in bold below.

[not(ancestor::ForInit)]
[not(ancestor::LambdaExpression)] [not(../../VariableDeclarator and ../../../LocalVariableDeclaration and ../../../../ForStatement)]
[not((ancestor::FormalParameter) and (ancestor::TryStatement))]

  • Optionally, you can also make further tweaks to the ruleset files.

  • Recreate the jar file using the modified naming.xml. This command does that:

    jar cf pmd-java-5.8.1.jar net rulesets META-INF

I don't know what flavor and version of the PMD plugin you have, but they should all be using pmd-java-5.8.1.jar or some earlier version of it. I just did a simple proof-of-concept using PMD itself rather than a plugin, and verified it from the command line for a class with this method:

void test() {
    Consumer<String> consumer = (String s) -> System.out.println(s);
    consumer.accept("Hello world!!!");
}

Version 5.8.1 of PMD reported the violation shown below for the lambda variable in that code:

violation for short variable

However, after modifying naming.xml as described above that violation was gone.

Newer PMD version uses ShortVariable rule in naming ruleset now. I used this in my ruleset.xml to make the error go away for just lambdas. It still catches short non-lambda variables.

<rule ref="rulesets/java/naming.xml/ShortVariable">
    <properties>
        <property
                name="violationSuppressXPath" value=".[ancestor::LambdaExpression]"/>
    </properties>
</rule>
Related