A DESCRIPTION OF THE PROBLEM :
I have a javac plug-in (see its source code below), that passes through an AST and tries to call Trees.getScope for an IdentifierTree in NewClassTree. The plug-in is run on the next code:
==========
class A {}
class B {
public class I {
}
void m() {
this.new I() {
};
}
}
==========
When Trees.getScope is invoked for a TreePath of an IdentifierNode in `this.new I() { };`, AssertionError is thrown.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the plug-in:
$ javac src/main/java/example/TestPlugin.java -d out/
$ cp -r src/main/resources/* out/
$ cd out
$ jar cvf test-plugin.jar *
2. Run plug-in on the given example:
$ javac Bad.java -Xplugin:TestPlugin -cp out/test-plugin.jar
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Plug-in should print:
==========
Resolving scope of anonymous class ident...
Success: ...
==========
ACTUAL -
com.sun.tools.javac.util.ClientCodeException: java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.api.ClientCodeWrapper$WrappedTaskListener.finished(ClientCodeWrapper.java:858)
at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1394)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1351)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:946)
at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:317)
at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:176)
at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:64)
at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:50)
Caused by: java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.util.Assert.error(Assert.java:155)
at jdk.compiler/com.sun.tools.javac.util.Assert.check(Assert.java:46)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:5390)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribClass(Attr.java:5353)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribClass(Attr.java:5184)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitClassDef(Attr.java:980)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:819)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStat(Attr.java:751)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitAnonymousClassDefinition(Attr.java:2960)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitNewClass(Attr.java:2851)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1852)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribExpr(Attr.java:730)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitExec(Attr.java:2276)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1584)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStat(Attr.java:751)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStats(Attr.java:770)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitBlock(Attr.java:1448)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1091)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.DeferredAttr.attribSpeculative(DeferredAttr.java:500)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribToTree(Attr.java:429)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStatToTree(Attr.java:422)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.attribStatToTree(JavacTrees.java:943)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.getAttrContext(JavacTrees.java:918)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:798)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:166)
at example.TestPlugin$Visitor.visitIdentifier(TestPlugin.java:79)
...
---------- BEGIN SOURCE ----------
Plugin source code (src/main/java/example/TestPlugin.java):
==========
package example;
import com.sun.source.tree.*;
import com.sun.source.util.*;
public class TestPlugin implements Plugin {
@Override
public String getName() {
return "TestPlugin";
}
@Override
public void init(JavacTask javacTask, String... strings) {
Trees trees = Trees.instance(javacTask);
Visitor visitor = new Visitor(trees);
javacTask.addTaskListener(new TaskListener() {
@Override
public void finished(TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.ANALYZE) return;
e.getCompilationUnit().accept(visitor, null);
}
});
}
private static class Visitor extends SimpleTreeVisitor<Void, Void> {
private final Trees trees;
private CompilationUnitTree compilationUnit;
private Visitor(Trees trees) {
this.trees = trees;
}
@Override
public Void visitCompilationUnit(CompilationUnitTree node, Void unused) {
this.compilationUnit = node;
for (Tree decl : node.getTypeDecls()) {
decl.accept(this, unused);
}
return unused;
}
@Override
public Void visitClass(ClassTree node, Void unused) {
for (Tree member : node.getMembers()) {
member.accept(this, unused);
}
return unused;
}
@Override
public Void visitMethod(MethodTree node, Void unused) {
for (StatementTree statement : node.getBody().getStatements()) {
statement.accept(this, unused);
}
return unused;
}
@Override
public Void visitExpressionStatement(ExpressionStatementTree node, Void unused) {
node.getExpression().accept(this, unused);
return unused;
}
@Override
public Void visitNewClass(NewClassTree node, Void unused) {
node.getIdentifier().accept(this, unused);
return unused;
}
@Override
public Void visitIdentifier(IdentifierTree node, Void unused) {
if (compilationUnit == null) return unused;
TreePath treePath = TreePath.getPath(compilationUnit, node);
if (treePath == null) return unused;
System.out.println("Resolving scope of anonymous class ident...");
Scope scope = trees.getScope(treePath);
System.out.println("Success: " + scope);
return unused;
}
}
}
==========
src/main/resources/META-INF/services/com.sun.source.util.Plugin:
==========
example.TestPlugin
==========
Code that causes the crash (Bad.java):
==========
class A {}
class B {
public class I {
}
void m() {
this.new I() {
};
}
}
==========
---------- END SOURCE ----------
FREQUENCY : always
I have a javac plug-in (see its source code below), that passes through an AST and tries to call Trees.getScope for an IdentifierTree in NewClassTree. The plug-in is run on the next code:
==========
class A {}
class B {
public class I {
}
void m() {
this.new I() {
};
}
}
==========
When Trees.getScope is invoked for a TreePath of an IdentifierNode in `this.new I() { };`, AssertionError is thrown.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the plug-in:
$ javac src/main/java/example/TestPlugin.java -d out/
$ cp -r src/main/resources/* out/
$ cd out
$ jar cvf test-plugin.jar *
2. Run plug-in on the given example:
$ javac Bad.java -Xplugin:TestPlugin -cp out/test-plugin.jar
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Plug-in should print:
==========
Resolving scope of anonymous class ident...
Success: ...
==========
ACTUAL -
com.sun.tools.javac.util.ClientCodeException: java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.api.ClientCodeWrapper$WrappedTaskListener.finished(ClientCodeWrapper.java:858)
at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1394)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1351)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:946)
at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:317)
at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:176)
at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:64)
at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:50)
Caused by: java.lang.AssertionError
at jdk.compiler/com.sun.tools.javac.util.Assert.error(Assert.java:155)
at jdk.compiler/com.sun.tools.javac.util.Assert.check(Assert.java:46)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:5390)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribClass(Attr.java:5353)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribClass(Attr.java:5184)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitClassDef(Attr.java:980)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:819)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStat(Attr.java:751)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitAnonymousClassDefinition(Attr.java:2960)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitNewClass(Attr.java:2851)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1852)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribExpr(Attr.java:730)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitExec(Attr.java:2276)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1584)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStat(Attr.java:751)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStats(Attr.java:770)
at jdk.compiler/com.sun.tools.javac.comp.Attr.visitBlock(Attr.java:1448)
at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1091)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:677)
at jdk.compiler/com.sun.tools.javac.comp.DeferredAttr.attribSpeculative(DeferredAttr.java:500)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribToTree(Attr.java:429)
at jdk.compiler/com.sun.tools.javac.comp.Attr.attribStatToTree(Attr.java:422)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.attribStatToTree(JavacTrees.java:943)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.getAttrContext(JavacTrees.java:918)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:798)
at jdk.compiler/com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:166)
at example.TestPlugin$Visitor.visitIdentifier(TestPlugin.java:79)
...
---------- BEGIN SOURCE ----------
Plugin source code (src/main/java/example/TestPlugin.java):
==========
package example;
import com.sun.source.tree.*;
import com.sun.source.util.*;
public class TestPlugin implements Plugin {
@Override
public String getName() {
return "TestPlugin";
}
@Override
public void init(JavacTask javacTask, String... strings) {
Trees trees = Trees.instance(javacTask);
Visitor visitor = new Visitor(trees);
javacTask.addTaskListener(new TaskListener() {
@Override
public void finished(TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.ANALYZE) return;
e.getCompilationUnit().accept(visitor, null);
}
});
}
private static class Visitor extends SimpleTreeVisitor<Void, Void> {
private final Trees trees;
private CompilationUnitTree compilationUnit;
private Visitor(Trees trees) {
this.trees = trees;
}
@Override
public Void visitCompilationUnit(CompilationUnitTree node, Void unused) {
this.compilationUnit = node;
for (Tree decl : node.getTypeDecls()) {
decl.accept(this, unused);
}
return unused;
}
@Override
public Void visitClass(ClassTree node, Void unused) {
for (Tree member : node.getMembers()) {
member.accept(this, unused);
}
return unused;
}
@Override
public Void visitMethod(MethodTree node, Void unused) {
for (StatementTree statement : node.getBody().getStatements()) {
statement.accept(this, unused);
}
return unused;
}
@Override
public Void visitExpressionStatement(ExpressionStatementTree node, Void unused) {
node.getExpression().accept(this, unused);
return unused;
}
@Override
public Void visitNewClass(NewClassTree node, Void unused) {
node.getIdentifier().accept(this, unused);
return unused;
}
@Override
public Void visitIdentifier(IdentifierTree node, Void unused) {
if (compilationUnit == null) return unused;
TreePath treePath = TreePath.getPath(compilationUnit, node);
if (treePath == null) return unused;
System.out.println("Resolving scope of anonymous class ident...");
Scope scope = trees.getScope(treePath);
System.out.println("Success: " + scope);
return unused;
}
}
}
==========
src/main/resources/META-INF/services/com.sun.source.util.Plugin:
==========
example.TestPlugin
==========
Code that causes the crash (Bad.java):
==========
class A {}
class B {
public class I {
}
void m() {
this.new I() {
};
}
}
==========
---------- END SOURCE ----------
FREQUENCY : always