Search code examples
mavenpmd

UnusedFormalParameter vs. AvoidDuplicateLiterals in maven-pmd-plugin


I'm using the built-in rulesets strings.xml and unusedcode.xml with

<?xml version="1.0"?>
<ruleset name="Custom ruleset"
        xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    <description>
        The default ruleset
    </description>
    <rule ref="rulesets/java/strings.xml"/>
    <rule ref="rulesets/java/unusedcode.xml"/>
</ruleset>

in the maven-pmd-plugin as follows:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.8</version>
    <executions>
        <execution>
            <id>pmd-check</id>
            <phase>validate</phase>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <printFailingErrors>true</printFailingErrors>
        <detail>true</detail>
        <rulesets>
            <ruleset>${basedir}/src/main/resources/ruleset.xml</ruleset>
        </rulesets>
    </configuration>
</plugin>

So that I get the following problem in the following use case:

public class NewClass {
    private final static String PMD_UNUSED_FORMAL_PARAMETER = "PMD.UnusedFormalParameter";

    @SuppressWarnings(PMD_UNUSED_FORMAL_PARAMETER)
    private void someMethod1(Object parameter1) {
        System.out.println("someMethod1");
    }

    @SuppressWarnings("PMD.UnusedFormalParameter")
    private void someMethod2(Object parameter1) {
        System.out.println("someMethod2");
    }

    @SuppressWarnings("PMD.UnusedFormalParameter")
    private void someMethod3(Object parameter1) {
        System.out.println("someMethod3");
    }

    @SuppressWarnings("PMD.UnusedFormalParameter")
    private void someMethod4(Object parameter1) {
        System.out.println("someMethod4");
    }

    public static void main(String[] args) {
        NewClass newClazz = new NewClass();
        newClazz.someMethod1(null);
        newClazz.someMethod2(null);
        newClazz.someMethod3(null);
    }
}

Having the annotation parameter value "PMD.UnusedFormalParameter" appear 4 times causes an AvoidDuplicateLiterals violation. replacing the string with the commented out private final static constant causes the annotation to have no effect and thus an UnusedFormalParameter violation.

I don't know about the internals of PMD. As an out-of-the-box user it appears strange that PMD both doesn't substitute the variable with its value (even though that's probably a context sensitive task it should be possible within the scope of static code analysis, it's just complex) and that UnusedFormalParameter doesn't exclude string values which are obviously used to suppress other checks and are only there because of PMD.

I'm using maven-pmd-plugin 3.8.


Solution

  • As for your issue, there are currently 2 ways you can work around this:

    1. AvoidDuplicateLiterals allows for a skipAnnotations property that can be set to true to ignore literals in annotations. Of course that would ignore all literals in all annotations, not just @SuppressWarnings
    2. All rules allow you to configure a violationSuppressXPath property with an XPath expression of expressions to ignore. For instance, on this case, you can set it to the AvoidDuplicateLiterals rule to ignore literals on @SuppressWarnings. I believe the proper expression for this would be //Annotation//Name[@Image = "SuppressWarnings" or @Image = "java.lang.SuppressWarnings"]/..//Literal (you'd have to test it to make sure)

    I don't know about the internals of PMD. As an out-of-the-box user it appears strange that PMD both doesn't substitute the variable with its value (even though that's probably a context sensitive task it should be possible within the scope of static code analysis, it's just complex)

    You are right, this behavior is not currently supported. I've just added an issue on Github to track the request. Feel free to chip in.