When I execute pmd 5.4.1 without -auxclasspath, I get no rule violation:
$ ./pmd-bin-5.4.1/bin/run.sh pmd -d src -R java-unusedcode
With -auxclasspath containing logback-json-core-0.1.4.jar, I get an UnusedPrivateMethod violation.
$ ./pmd-bin-5.4.1/bin/run.sh pmd -d src -R java-unusedcode -auxclasspath logback-json-core-0.1.4.jar
/Users/david.byron/src/tmp/pmd_false_positive/src/Foo.java:23: Avoid unused private methods such as 'blah(ConsoleAppender,JsonLayoutBase)'.
The code in question is:
import ch.qos.logback.contrib.json.JsonLayoutBase;
import ch.qos.logback.core.ConsoleAppender;
class JsonAccessLogLayout extends JsonHttpLayout<IAccessEvent> {
}
public class Foo {
private final ConsoleAppender<IAccessEvent> appender;
private final JsonLayoutBase<IAccessEvent> layoutOne;
private final JsonAccessLogLayout layoutTwo;
public Foo() {
bar(appender, layoutOne);
blah(appender, layoutTwo);
}
private <E> void bar(ConsoleAppender<E> appender, JsonLayoutBase<E> layout) {
appender;
layout;
}
private <E> void blah(ConsoleAppender<E> appender, JsonLayoutBase<E> layout) {
appender;
layout;
}
}
Note that the only complaint is about blah.
logback-json-core-0.1.4.jar contains JsonLayoutBase. When I build the real version of this code, I get ConsoleAppender from logback-core-1.1.7.jar. Adding that to auxclasspath doesn't make the violation disappear.
-DB
Hm... you are calling blah with layoutTwo, which is a
JsonAccessLogLayout- and PMD can't figure out, that this is a JsonLayoutBase, so it doesn't count this method calls.I see two problems here:
JsonAccessLayout is defined in the same class. PMD's type system doesn't understand this - as PMD doesn't compile the source code, it wouldn't know about JsonAccessLogLayout. It might work if you add the compiled Foo.class and Foo$JsonAccessLogLayout.class to the auxclasspath, but I'm not sure. It is anyway usually necessary, to add the project's compiled classes to the auxclasspath, too, as otherwise PMD would only know about third-party-libraries.
I don't know where
JsonHttpLayoutcomes from. You'll need to make sure, that this class (and any intermediates) are on the auxclasspath, too.I don't think the ConsoleAppender is the problem, as the call to "bar" is detected.
Grrr, sorry for screwing up the sample...I think my real code does the stuff you mention and still has the false positive. JsonHttpLayout extends JsonLayoutBase, like this:
Adding the extra level with JsonAccessLogLayout isn't relevant.
I included another jar on the classpath that has JsonHttpLayout in it in the same package. That jar also has:
and
In my real code, this Foo class is also in the same jar file as JsonHttpLayout, IAccessEvent and IRequestEvent.
Here's the adjusted sample. With both jars on the auxclasspath, as well as only one or the other, I get the warning. With no auxclasspath, no warning.
Last edit: David Byron 2016-04-30
Hm... I can't reproduce it. I've created small package with your case, but I don't get the violation - see the attached zip file.
I get the violation, if I don't have "target" on the auxclasspath - Can you double check, that you first compile your project, then run pmd and making sure, the class files of your project are on the auxclasspath with the logback files?
The reason, why there is no violation without the auxclasspath is this, that PMD won't try to match the argument types and considers just the counts. It works well, as long as the methods are not overloaded.
Interesting. In real life gradle is the one actually running pmd for me. I've attached a zip file that's almost like yours, but with a build.gradle instead of build.sh, and the source files moved.
and that main.html file contains:
When I run gradle with --debug, I see this:
which doesn't contain the class files built here. Other potentially interesting debug messages:
and similar messages for foo.IAccessEvent, foo.IRequestEvent, foo.JsonHttpLayout.
I'm not sure what I can do to convince gradle to look at our own class files, or exactly what to report to the gradle folks if that's the right next step.
Thanks much for your help.
-DB
Thanks for your gradle-based sample project. I was able to find the problem: Gradle indeed doesn't add the output directory of the project to the auxclasspath. There is a workaround available:
I created a pull request on the gradle side, to make this configuration the default, so that the special configuration isn't needed in the future anymore.
I'll close this ticket here - let me know, in case you still have some issues.
Thanks much for the pull request there. That's great.