Menu

#1468 UnusedPrivateMethod with auxclasspath

PMD-5.4.2
closed
None
PMD
3-Major
Bug
5.4.1
UnusedPrivateMethod
2016-05-29
2016-04-07
David Byron
No

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

Discussion

  • Andreas Dangel

    Andreas Dangel - 2016-04-30

    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:

    1. 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.

    2. I don't know where JsonHttpLayout comes 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.

     
  • David Byron

    David Byron - 2016-04-30

    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:

    public class JsonHttpLayout<E extends IRequestEvent> extends JsonLayoutBase<E> {
    

    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:

    public interface IAccessEvent extends IRequestEvent {
    }
    

    and

    public interface IRequestEvent {
    }
    

    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.

    package foo;
    
    import ch.qos.logback.contrib.json.JsonLayoutBase;
    import ch.qos.logback.core.ConsoleAppender;
    
    public class Foo {
       private final ConsoleAppender<IAccessEvent> appender;
    
       private final JsonLayoutBase<IAccessEvent> layoutOne;
       private final JsonHttpLayout<IAccessEvent> 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;
       }
    }
    
     

    Last edit: David Byron 2016-04-30
  • Andreas Dangel

    Andreas Dangel - 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.

     
  • David Byron

    David Byron - 2016-05-07

    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.

    $ ./gradlew pmdMain
    :pmdMain FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':pmdMain'.
    > 1 PMD rule violations were found. See the report at: file:///Users/david.byron/src/tmp/pmd_false_positive/bug-1468-gradle/build/reports/pmd/main.html
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    BUILD FAILED
    
    Total time: 1.009 secs
    

    and that main.html file contains:

    1   /Users/david.byron/src/tmp/pmd_false_positive/bug-1468-gradle/src/main/java/foo/Foo.java    22  Avoid unused private methods such as 'blah(ConsoleAppender,JsonLayoutBase)'.
    

    When I run gradle with --debug, I see this:

    14:22:12.977 [DEBUG] [org.gradle.api.internal.project.ant.AntLoggingAdapter] Using auxclasspath: /Users/david.byron/.gradle/caches/modules-2/files-2.1/ch.qos.logback.contrib/logback-json-core/0.1.4/fe249958693754e74044739014012a52dcf39886/logback-json-core-0.1.4.jar:/Users/david.byron/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.0.9/41916886a1df068ad1dfea9bcc649a7b8ea4553e/logback-core-1.0.9.jar
    

    which doesn't contain the class files built here. Other potentially interesting debug messages:

    14:22:13.106 [DEBUG] [org.gradle.api.internal.project.ant.AntLoggingAdapter] Could not find class foo.Foo, due to: java.lang.ClassNotFoundException: foo.Foo
    14:22:13.107 [DEBUG] [net.sourceforge.pmd.lang.java.typeresolution.ClassTypeResolver] Could not find class foo.Foo, due to: java.lang.ClassNotFoundException: foo.Foo
    

    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

     
  • Andreas Dangel

    Andreas Dangel - 2016-05-29
    • status: open --> closed
    • assigned_to: Andreas Dangel
    • Milestone: New Tickets --> PMD-5.4.2
     
  • Andreas Dangel

    Andreas Dangel - 2016-05-29

    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:

    pmdMain {
       classpath = files(sourceSets.main.compileClasspath, sourceSets.main.output)
    }
    

    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.

     
  • David Byron

    David Byron - 2016-05-29

    Thanks much for the pull request there. That's great.

     

Log in to post a comment.