JDK-6852595 : Accessing scope using JSR199 API on erroneous tree causes Illegal Argument Exception
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: unknown
  • Submitted: 2009-06-18
  • Updated: 2012-01-13
  • Resolved: 2012-01-13
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 7
7 b64Fixed
Related Reports
Relates :  
Description
The following programs compiles and runs fine on JDK6/6-open, but it fails at runtime with an IllegalArgumentException with JDK 7

import com.sun.source.util.JavacTask;
import com.sun.source.tree.*;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;

class TestAPI {
    static class MyFileObject extends SimpleJavaFileObject {
        private String text;
        public MyFileObject(String text) {
            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
            this.text = text;
        }
        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return text;
        }
    }
    
    public static void main(String[] args) throws IOException {        
        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();

        String code = "class BadName { Object o = j; }";
        
        JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, Arrays.asList(new MyFileObject(code)));
        
        Iterable<? extends CompilationUnitTree> compUnits = ct.parse();
		CompilationUnitTree cu = compUnits.iterator().next();
		ClassTree cdef = (ClassTree)cu.getTypeDecls().get(0);
		JCVariableDecl vdef = (JCVariableDecl)cdef.getMembers().get(0);		
		TreePath path = TreePath.getPath(cu, vdef.init);
		Trees.instance(ct).getScope(path);
    }
}

Output with JDK6 is:

null:0: cannot find symbol
symbol  : variable j
location: class BadName

Output with JDK7 is:

Exception in thread "main" java.lang.IllegalArgumentException
        at com.sun.tools.javac.util.JCDiagnostic.<init>(JCDiagnostic.java:276)
        at com.sun.tools.javac.util.JCDiagnostic$Factory.error(JCDiagnostic.java:86)
        at com.sun.tools.javac.util.AbstractLog.error(AbstractLog.java:86)
        at com.sun.tools.javac.comp.Resolve$ResolveError.report(Resolve.java:1667)
        at com.sun.tools.javac.comp.Resolve.access(Resolve.java:1093)
        at com.sun.tools.javac.comp.Resolve.access(Resolve.java:1113)
        at com.sun.tools.javac.comp.Resolve.resolveIdent(Resolve.java:1176)
        at com.sun.tools.javac.comp.Attr.visitIdent(Attr.java:1755)
        at com.sun.tools.javac.tree.JCTree$JCIdent.accept(JCTree.java:1679)
        at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:372)
        at com.sun.tools.javac.comp.Attr.attribExpr(Attr.java:396)
        at com.sun.tools.javac.comp.Attr.attribExprToTree(Attr.java:301)
        at com.sun.tools.javac.api.JavacTrees.attribExprToTree(JavacTrees.java:302)
        at com.sun.tools.javac.api.JavacTrees.getAttrContext(JavacTrees.java:282)
        at com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:199)
        at com.sun.tools.javac.api.JavacTrees.getScope(JavacTrees.java:78)
        at TestAPI.main(TestAPI.java:41)

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL http://hg.openjdk.java.net/jdk7/tl/langtools/rev/18e0269f25e3
24-06-2009

EVALUATION this problem started in jdk 7 b32 with CR 6724071 which is the Log refactoring. I inspected the code of that changeset a bit and discovered that the Log.useSource used to create a dummy DiagnosticSource if called with a null argument. After the refactoring, calling Log.useSource(null) just sets the source to null - which is problematic for JCDiagnostic, as the constructor of that class checks that diagnostics with a non empty position should have a corresponding source (in this case position is set but source is null). This is also confirmed by looking at the output of my test executed against b31: null:0: cannot find symbol symbol : variable j location: class BadName As it can be seen, there's indeed a DiagnosticSource there - only it returns null for almost everything (most noticeably filename). Which means that the test carried out inside JCDiagnostic's constructor succeeds because source != null. I think that the new behavior is more precise - it's better to have null rather than a dummy DiagnosticSource that prints out wrong values - however this means that we should pay extra-care to all usages of Log.useSource(null) [4 of them]. It appears that not all the usages of useSource(null) can be replaced with useSource(env.toplevel.sourcefile) - in two cases there's no AttrEnv available. *) JavacTaskImpl:526 *) JavaCompiler:643
18-06-2009