Mon, 06 Sep 2010 12:55:09 -0700
6930507: Symbols for anonymous and local classes made too late for use by java tree API
Reviewed-by: mcimadamore
1.1 --- a/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Fri Sep 03 12:00:21 2010 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Mon Sep 06 12:55:09 2010 -0700 1.3 @@ -45,6 +45,7 @@ 1.4 import com.sun.source.util.SourcePositions; 1.5 import com.sun.source.util.TreePath; 1.6 import com.sun.source.util.Trees; 1.7 +import com.sun.tools.javac.code.Flags; 1.8 import com.sun.tools.javac.code.Symbol.ClassSymbol; 1.9 import com.sun.tools.javac.code.Symbol.TypeSymbol; 1.10 import com.sun.tools.javac.code.Symbol; 1.11 @@ -189,8 +190,24 @@ 1.12 } 1.13 1.14 public Element getElement(TreePath path) { 1.15 - Tree t = path.getLeaf(); 1.16 - return TreeInfo.symbolFor((JCTree) t); 1.17 + JCTree tree = (JCTree) path.getLeaf(); 1.18 + Symbol sym = TreeInfo.symbolFor(tree); 1.19 + if (sym == null && TreeInfo.isDeclaration(tree)) { 1.20 + for (TreePath p = path; p != null; p = p.getParentPath()) { 1.21 + JCTree t = (JCTree) p.getLeaf(); 1.22 + if (t.getTag() == JCTree.CLASSDEF) { 1.23 + JCClassDecl ct = (JCClassDecl) t; 1.24 + if (ct.sym != null) { 1.25 + if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) { 1.26 + attr.attribClass(ct.pos(), ct.sym); 1.27 + sym = TreeInfo.symbolFor(tree); 1.28 + } 1.29 + break; 1.30 + } 1.31 + } 1.32 + } 1.33 + } 1.34 + return sym; 1.35 } 1.36 1.37 public TypeMirror getTypeMirror(TreePath path) {
2.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Fri Sep 03 12:00:21 2010 -0700 2.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Sep 06 12:55:09 2010 -0700 2.3 @@ -637,6 +637,18 @@ 2.4 } 2.5 } 2.6 2.7 + public static boolean isDeclaration(JCTree node) { 2.8 + node = skipParens(node); 2.9 + switch (node.getTag()) { 2.10 + case JCTree.CLASSDEF: 2.11 + case JCTree.METHODDEF: 2.12 + case JCTree.VARDEF: 2.13 + return true; 2.14 + default: 2.15 + return false; 2.16 + } 2.17 + } 2.18 + 2.19 /** If this tree is an identifier or a field, return its symbol, 2.20 * otherwise return null. 2.21 */
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/tools/javac/api/TestGetElement.java Mon Sep 06 12:55:09 2010 -0700 3.3 @@ -0,0 +1,235 @@ 3.4 +/* 3.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.23 + * or visit www.oracle.com if you need additional information or have any 3.24 + * questions. 3.25 + */ 3.26 + 3.27 +/* 3.28 + * @test 3.29 + * @bug 6930507 3.30 + * @summary Symbols for anonymous and local classes made too late for use by java tree API 3.31 + */ 3.32 + 3.33 +import java.io.*; 3.34 +import java.util.*; 3.35 +import javax.annotation.processing.*; 3.36 +import javax.lang.model.SourceVersion; 3.37 +import javax.lang.model.element.*; 3.38 +import javax.tools.Diagnostic; 3.39 +import static javax.lang.model.util.ElementFilter.*; 3.40 + 3.41 +import com.sun.source.tree.*; 3.42 +import com.sun.source.util.*; 3.43 + 3.44 +@SupportedOptions({"test", "last"}) 3.45 +@SupportedAnnotationTypes("*") 3.46 +public class TestGetElement extends AbstractProcessor { 3.47 + public static void main(String... args) throws Exception { 3.48 + new TestGetElement().run(); 3.49 + } 3.50 + 3.51 + public TestGetElement() { } 3.52 + 3.53 + public void run() throws Exception { 3.54 + final String testSrc = System.getProperty("test.src"); 3.55 + final String testClasses = System.getProperty("test.classes"); 3.56 + final String myClassName = getClass().getName(); 3.57 + final String mySrc = new File(testSrc, myClassName + ".java").getPath(); 3.58 + 3.59 + final int NUM_TESTS = 90; // #decls in this source file 3.60 + for (int i = 1; i <= NUM_TESTS; i++) { 3.61 + System.err.println("test " + i); 3.62 + File testDir = new File("test" + i); 3.63 + File classesDir = new File(testDir, "classes"); 3.64 + classesDir.mkdirs(); 3.65 + String[] args = { 3.66 + "-d", classesDir.getPath(), 3.67 + "-processorpath", testClasses, 3.68 + "-processor", myClassName, 3.69 + "-proc:only", 3.70 + "-Atest=" + i, 3.71 + "-Alast=" + (i == NUM_TESTS), 3.72 + mySrc 3.73 + }; 3.74 + 3.75 +// System.err.println("compile: " + Arrays.asList(args)); 3.76 + 3.77 + StringWriter sw = new StringWriter(); 3.78 + PrintWriter pw = new PrintWriter(sw); 3.79 + int rc = com.sun.tools.javac.Main.compile(args, pw); 3.80 + pw.close(); 3.81 + String out = sw.toString(); 3.82 + if (out != null) 3.83 + System.err.println(out); 3.84 + if (rc != 0) { 3.85 + System.err.println("compilation failed: rc=" + rc); 3.86 + errors++; 3.87 + } 3.88 + } 3.89 + 3.90 + if (errors > 0) 3.91 + throw new Exception(errors + " errors occurred"); 3.92 + } 3.93 + 3.94 + 3.95 + int errors; 3.96 + 3.97 + public boolean process(Set<? extends TypeElement> annotations, 3.98 + RoundEnvironment roundEnvironment) 3.99 + { 3.100 + if (roundEnvironment.processingOver()) 3.101 + return true; 3.102 + 3.103 + Map<String,String> options = processingEnv.getOptions(); 3.104 + int test = Integer.parseInt(options.get("test")); 3.105 + boolean _last = Boolean.parseBoolean(options.get("last")); 3.106 + 3.107 + Trees trees = Trees.instance(processingEnv); 3.108 + Scanner scanner = new Scanner(trees, _last); 3.109 + int nelems = 0; 3.110 + for (TypeElement e : typesIn(roundEnvironment.getRootElements())) { 3.111 + nelems += scanner.scan(trees.getPath(e), test); 3.112 + } 3.113 + 3.114 + Messager m = processingEnv.getMessager(); 3.115 + int EXPECT = 1; 3.116 + if (nelems != EXPECT) { 3.117 + m.printMessage(Diagnostic.Kind.ERROR, 3.118 + "Unexpected number of elements found: " + nelems + " expected: " + EXPECT); 3.119 + } 3.120 + return true; 3.121 + } 3.122 + 3.123 + @Override 3.124 + public SourceVersion getSupportedSourceVersion() { 3.125 + return SourceVersion.latest(); 3.126 + } 3.127 + 3.128 + class Scanner extends TreePathScanner<Integer,Integer> { 3.129 + final Trees trees; 3.130 + final boolean last; 3.131 + int count; 3.132 + 3.133 + Scanner(Trees trees, boolean last) { 3.134 + this.trees = trees; 3.135 + this.last = last; 3.136 + } 3.137 + 3.138 + @Override 3.139 + public Integer visitClass(ClassTree tree, Integer test) { 3.140 + return reduce(check(test), super.visitClass(tree, test)); 3.141 + } 3.142 + 3.143 + @Override 3.144 + public Integer visitMethod(MethodTree tree, Integer test) { 3.145 + return reduce(check(test), super.visitMethod(tree, test)); 3.146 + } 3.147 + 3.148 + @Override 3.149 + public Integer visitVariable(VariableTree tree, Integer test) { 3.150 + return reduce(check(test), super.visitVariable(tree, test)); 3.151 + } 3.152 + 3.153 + @Override 3.154 + public Integer reduce(Integer i1, Integer i2) { 3.155 + if (i1 == null || i1.intValue() == 0) 3.156 + return i2; 3.157 + if (i2 == null || i2.intValue() == 0) 3.158 + return i1; 3.159 + return (i1 + i2); 3.160 + } 3.161 + 3.162 + int check(int test) { 3.163 + count++; 3.164 + 3.165 + if (count != test) 3.166 + return 0; 3.167 + 3.168 + TreePath p = getCurrentPath(); 3.169 + Element e = trees.getElement(p); 3.170 + 3.171 + String text = p.getLeaf().toString().replaceAll("\\s+", " ").trim(); 3.172 + int MAXLEN = 40; 3.173 + if (text.length() > MAXLEN) 3.174 + text = text.substring(0, MAXLEN - 3) + "..."; 3.175 + 3.176 + System.err.println(String.format("%3d: %-" + MAXLEN + "s -- %s", 3.177 + count, text, 3.178 + (e == null ? "null" : e.getKind() + " " + e))); 3.179 + 3.180 + Messager m = processingEnv.getMessager(); 3.181 + if (e == null) { 3.182 + m.printMessage(Diagnostic.Kind.ERROR, "Null element found for " + text); 3.183 + return 0; 3.184 + } 3.185 + 3.186 + if (last && !e.getSimpleName().contentEquals("last")) { 3.187 + m.printMessage(Diagnostic.Kind.ERROR, "Unexpected name in last test: " 3.188 + + e.getSimpleName() + ", expected: last"); 3.189 + } 3.190 + 3.191 + return 1; 3.192 + } 3.193 + } 3.194 + 3.195 + // following are all fodder for the test 3.196 + 3.197 + class MemberClass { 3.198 + class NestedMemberClass { } 3.199 + } 3.200 + 3.201 + { 3.202 + class InnerClassInInit { } 3.203 + Object o = new Object() { }; 3.204 + } 3.205 + 3.206 + TestGetElement(TestGetElement unused) { 3.207 + class InnerClassInConstr { } 3.208 + Object o = new Object() { }; 3.209 + } 3.210 + 3.211 + void m() { 3.212 + class InnerClassInMethod { } 3.213 + Object o = new Object() { }; 3.214 + 3.215 + class C { 3.216 + class MemberClass { 3.217 + class NestedMemberClass { } 3.218 + } 3.219 + 3.220 + { 3.221 + class InnerClassInInit { } 3.222 + Object o = new Object() { }; 3.223 + } 3.224 + 3.225 + C(Object unused) { 3.226 + class InnerClassInConstr { } 3.227 + Object o = new Object() { }; 3.228 + } 3.229 + 3.230 + void m() { 3.231 + class InnerClassInMethod { } 3.232 + Object o = new Object() { }; 3.233 + } 3.234 + } 3.235 + } 3.236 + 3.237 + int last; // this name is verified by the test to make sure that all decls are checked 3.238 +}
4.1 --- a/test/tools/javac/processing/model/element/TestAnonClassNames.java Fri Sep 03 12:00:21 2010 -0700 4.2 +++ b/test/tools/javac/processing/model/element/TestAnonClassNames.java Mon Sep 06 12:55:09 2010 -0700 4.3 @@ -27,8 +27,7 @@ 4.4 * @summary Test that reported names of anonymous classes are non-null. 4.5 * @author Joseph D. Darcy 4.6 * @build TestAnonSourceNames 4.7 - * @compile/fail -processor TestAnonSourceNames TestAnonClassNames.java 4.8 - * @build TestAnonClassNames 4.9 + * @compile -processor TestAnonSourceNames TestAnonClassNames.java 4.10 * @run main TestAnonClassNames 4.11 */ 4.12 4.13 @@ -40,10 +39,6 @@ 4.14 * 4.15 * Source files will be tested by the @compile line which runs 4.16 * TestAnonSourceNames as an annotation processor over this file. 4.17 - * This compile line is expected to fail until 6930507 is fixed. Once 4.18 - * bug 6930507 is fixed, the "@compile/fail -processor ..." and 4.19 - * following "@build..." steps can be replaced with a single "@compile 4.20 - * -processor ..." directive. 4.21 * 4.22 * Class files are tested by the @run command on this type. This 4.23 * class gets the names of classes with different nesting kinds,
5.1 --- a/test/tools/javac/processing/model/element/TestAnonSourceNames.java Fri Sep 03 12:00:21 2010 -0700 5.2 +++ b/test/tools/javac/processing/model/element/TestAnonSourceNames.java Mon Sep 06 12:55:09 2010 -0700 5.3 @@ -67,7 +67,7 @@ 5.4 Element element = trees.getElement(trees.getPath(cu, node)); 5.5 if (element == null) { 5.6 processingEnv.getMessager().printMessage(ERROR, 5.7 - "No element retreived for node named ''" + 5.8 + "No element retrieved for node named ''" + 5.9 node.getSimpleName() + "''."); 5.10 } else { 5.11