Search code examples
javajavacabstract-syntax-treejava-compiler-api

Java TreePathScanner doesn't call visitClass for new class statements without bodies


I'm trying to use the Java TreePathScanner API to determine the list of class files that will be generated from a given compilation. For example, the following source code:

public class InnerClass {
    private final InnerInnerClass clazz = new InnerInnerClass();

    private class InnerInnerClass {
    }
}

will generate the following files:

  • InnerClass.class
  • InnerClass$1.class
  • InnerClass$InnerInnerClass.class

However, in my TreePathScanner subclass, visitClass is only called twice, for the InnerClass class, and the InnerInnerClass classes, but not the anonymously named class created from the new class statement. Changing the source to the following works as expected:

public class InnerClass {
    private final InnerInnerClass clazz = new InnerInnerClass() { };

    private class InnerInnerClass {
    }
}

My tool's full source code is available here for reference, specifically ArtifactScanner.java.

Either this is a bug or a flaw in the API as there doesn't seem to be any other way to get all of the binary names that will be generated from a given compilation unit's source code. Am I missing something?


Solution

  • One of the JDK developers explained on this bug report that the observed behavior really is not a bug, and that the additional class files are generated as a result of the Java compiler backend which rewrites more complex language constructs into simpler ones before generating class files.

    The TreePathScanner API therefore does produce the correct output in this case, and the short of it is that TreePathScanner is the wrong solution to use for my use case (determining the list of class files that will be produced) and that com.sun.source.util.TaskListener, TaskEvent, and TaskEvent.Kind, and JavaFileManager.inferBinaryName should be used instead.