JDK-7090249 : IllegalStateException from Trees.getScope when called from JSR 199
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-09-13
  • Updated: 2012-02-24
  • Resolved: 2012-02-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b08Fixed
Related Reports
Relates :  
Description
If you invoke javac via CompilationTask.call, and invoke an annotation processor that calls Trees.getScope, javac will crash with IllegalStateException.

	at com.sun.tools.javac.api.JavacTaskImpl.prepareCompiler(JavacTaskImpl.java:157)
	at com.sun.tools.javac.api.JavacTaskImpl.enter(JavacTaskImpl.java:266)
	at com.sun.tools.javac.api.JavacTrees.getAttrContext(JavacTrees.java:271)
	at com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:230)
	at com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:84)
	at TestGetScope$Scanner.visitIdentifier(TestGetScope.java:97)
	at TestGetScope$Scanner.visitIdentifier(TestGetScope.java:93)
	at com.sun.tools.javac.tree.JCTree$JCIdent.accept(JCTree.java:1711)
	at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:67)
	at com.sun.source.util.TreeScanner.visitAnnotation(TreeScanner.java:376)
	at com.sun.tools.javac.tree.JCTree$JCAnnotation.accept(JCTree.java:2013)
	at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:67)
	at com.sun.source.util.TreeScanner.scan(TreeScanner.java:90)
	at com.sun.source.util.TreeScanner.visitModifiers(TreeScanner.java:372)
	at com.sun.tools.javac.tree.JCTree$JCModifiers.accept(JCTree.java:2040)
	at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:67)
	at com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:128)
	at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:618)
	at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:49)
	at TestGetScope.process(TestGetScope.java:80)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:752)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:681)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700(JavacProcessingEnvironment.java:97)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:988)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1122)
	at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1106)
	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:824)
	at com.sun.tools.javac.main.Main.compile(Main.java:417)
	... 9 more

Comments
EVALUATION The final part of the patch is to temporarily patch the JCMethodDecl with the copied tree while attributing the method to get the context for the scope.
13-09-2011

EVALUATION It is reasonably easy to fix the immediate problem described here, with this patch: $ hg diff src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java diff -r f1431cace56e src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java --- a/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Mon Sep 12 11:40:07 2011 -0700 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Mon Sep 12 17:41:39 2011 -0700 @@ -274,6 +274,9 @@ public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees) throws IOException { + if (trees == null && notYetEntered.isEmpty()) + return List.nil(); + prepareCompiler(); ListBuffer<JCCompilationUnit> roots = null; But, the regression test for the patch has shown up a nasty problem in JavacTrees.getScope. The regression test is using a standard anno processor to get access to elements, and Trees to get from elements to the corresponding Tree. Then, it uses a TreePathScanner to call Trees.getScope on IdentifierTree nodes. Seems reasonable so far, right? The problem is in the use of the Copier class in JavacTrees. This class is used to make temporary trees that can be attributed, to get a c.s.s.tree.Scope (based on an Env<AttrContext>) and then discarded. The problem is that the env contains a reference to the enclosing MethodDecl (which has not been copied), which contains a reference to the uncopied method body. Then, we can get problems in attribution, specifically in Attr.checkFirstConstructorStat, which is checking that the tree being attributed (which has been copied) is identically the same tree as the first statement in the method body (which has not been copied). Obviously, they're now different, and attribution fails.
13-09-2011

EVALUATION The problem is in JavacTrees.getAttrContext. > // if we're being invoked via from a JSR199 client, we need to make sure > // all the classes have been entered; if we're being invoked from JSR269, > // then the classes will already have been entered. > if (javacTaskImpl != null) { > try { > javacTaskImpl.enter(null); > } catch (IOException e) { > throw new Error("unexpected error while entering symbols: " + e); > } > } Technically, the comment is wrong. If we're being invoked from a true 199 client, that client can only call call(), which is intended to be functionally very similar to the command line activation. That's why call() simply delegates to compilerMain.compile. The comment should say comething like "if we being invoked from a Trees API client...." because that is the only way that you can call parse/analyze/generate directly. It follows that the test following the comment is therefore incorrect as well. (javacTaskImpl != null) is an insufficient test for javacTaskImpl being invoked via the methods on the Trees API. We need to add some sort of mode flag to JavacTaskImpl, so that we can test whether we need to call javacTaskImpl.enter(null) or not.
13-09-2011