6930507: Symbols for anonymous and local classes made too late for use by java tree API
Reviewed-by: mcimadamore
This commit is contained in:
parent
5b58b51e22
commit
c09fe5cafb
@ -45,6 +45,7 @@ import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.SourcePositions;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.Trees;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
@ -189,8 +190,24 @@ public class JavacTrees extends Trees {
|
||||
}
|
||||
|
||||
public Element getElement(TreePath path) {
|
||||
Tree t = path.getLeaf();
|
||||
return TreeInfo.symbolFor((JCTree) t);
|
||||
JCTree tree = (JCTree) path.getLeaf();
|
||||
Symbol sym = TreeInfo.symbolFor(tree);
|
||||
if (sym == null && TreeInfo.isDeclaration(tree)) {
|
||||
for (TreePath p = path; p != null; p = p.getParentPath()) {
|
||||
JCTree t = (JCTree) p.getLeaf();
|
||||
if (t.getTag() == JCTree.CLASSDEF) {
|
||||
JCClassDecl ct = (JCClassDecl) t;
|
||||
if (ct.sym != null) {
|
||||
if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
|
||||
attr.attribClass(ct.pos(), ct.sym);
|
||||
sym = TreeInfo.symbolFor(tree);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
public TypeMirror getTypeMirror(TreePath path) {
|
||||
|
@ -637,6 +637,18 @@ public class TreeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDeclaration(JCTree node) {
|
||||
node = skipParens(node);
|
||||
switch (node.getTag()) {
|
||||
case JCTree.CLASSDEF:
|
||||
case JCTree.METHODDEF:
|
||||
case JCTree.VARDEF:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** If this tree is an identifier or a field, return its symbol,
|
||||
* otherwise return null.
|
||||
*/
|
||||
|
235
langtools/test/tools/javac/api/TestGetElement.java
Normal file
235
langtools/test/tools/javac/api/TestGetElement.java
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6930507
|
||||
* @summary Symbols for anonymous and local classes made too late for use by java tree API
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.tools.Diagnostic;
|
||||
import static javax.lang.model.util.ElementFilter.*;
|
||||
|
||||
import com.sun.source.tree.*;
|
||||
import com.sun.source.util.*;
|
||||
|
||||
@SupportedOptions({"test", "last"})
|
||||
@SupportedAnnotationTypes("*")
|
||||
public class TestGetElement extends AbstractProcessor {
|
||||
public static void main(String... args) throws Exception {
|
||||
new TestGetElement().run();
|
||||
}
|
||||
|
||||
public TestGetElement() { }
|
||||
|
||||
public void run() throws Exception {
|
||||
final String testSrc = System.getProperty("test.src");
|
||||
final String testClasses = System.getProperty("test.classes");
|
||||
final String myClassName = getClass().getName();
|
||||
final String mySrc = new File(testSrc, myClassName + ".java").getPath();
|
||||
|
||||
final int NUM_TESTS = 90; // #decls in this source file
|
||||
for (int i = 1; i <= NUM_TESTS; i++) {
|
||||
System.err.println("test " + i);
|
||||
File testDir = new File("test" + i);
|
||||
File classesDir = new File(testDir, "classes");
|
||||
classesDir.mkdirs();
|
||||
String[] args = {
|
||||
"-d", classesDir.getPath(),
|
||||
"-processorpath", testClasses,
|
||||
"-processor", myClassName,
|
||||
"-proc:only",
|
||||
"-Atest=" + i,
|
||||
"-Alast=" + (i == NUM_TESTS),
|
||||
mySrc
|
||||
};
|
||||
|
||||
// System.err.println("compile: " + Arrays.asList(args));
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
int rc = com.sun.tools.javac.Main.compile(args, pw);
|
||||
pw.close();
|
||||
String out = sw.toString();
|
||||
if (out != null)
|
||||
System.err.println(out);
|
||||
if (rc != 0) {
|
||||
System.err.println("compilation failed: rc=" + rc);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors > 0)
|
||||
throw new Exception(errors + " errors occurred");
|
||||
}
|
||||
|
||||
|
||||
int errors;
|
||||
|
||||
public boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnvironment)
|
||||
{
|
||||
if (roundEnvironment.processingOver())
|
||||
return true;
|
||||
|
||||
Map<String,String> options = processingEnv.getOptions();
|
||||
int test = Integer.parseInt(options.get("test"));
|
||||
boolean _last = Boolean.parseBoolean(options.get("last"));
|
||||
|
||||
Trees trees = Trees.instance(processingEnv);
|
||||
Scanner scanner = new Scanner(trees, _last);
|
||||
int nelems = 0;
|
||||
for (TypeElement e : typesIn(roundEnvironment.getRootElements())) {
|
||||
nelems += scanner.scan(trees.getPath(e), test);
|
||||
}
|
||||
|
||||
Messager m = processingEnv.getMessager();
|
||||
int EXPECT = 1;
|
||||
if (nelems != EXPECT) {
|
||||
m.printMessage(Diagnostic.Kind.ERROR,
|
||||
"Unexpected number of elements found: " + nelems + " expected: " + EXPECT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
class Scanner extends TreePathScanner<Integer,Integer> {
|
||||
final Trees trees;
|
||||
final boolean last;
|
||||
int count;
|
||||
|
||||
Scanner(Trees trees, boolean last) {
|
||||
this.trees = trees;
|
||||
this.last = last;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitClass(ClassTree tree, Integer test) {
|
||||
return reduce(check(test), super.visitClass(tree, test));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitMethod(MethodTree tree, Integer test) {
|
||||
return reduce(check(test), super.visitMethod(tree, test));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitVariable(VariableTree tree, Integer test) {
|
||||
return reduce(check(test), super.visitVariable(tree, test));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer reduce(Integer i1, Integer i2) {
|
||||
if (i1 == null || i1.intValue() == 0)
|
||||
return i2;
|
||||
if (i2 == null || i2.intValue() == 0)
|
||||
return i1;
|
||||
return (i1 + i2);
|
||||
}
|
||||
|
||||
int check(int test) {
|
||||
count++;
|
||||
|
||||
if (count != test)
|
||||
return 0;
|
||||
|
||||
TreePath p = getCurrentPath();
|
||||
Element e = trees.getElement(p);
|
||||
|
||||
String text = p.getLeaf().toString().replaceAll("\\s+", " ").trim();
|
||||
int MAXLEN = 40;
|
||||
if (text.length() > MAXLEN)
|
||||
text = text.substring(0, MAXLEN - 3) + "...";
|
||||
|
||||
System.err.println(String.format("%3d: %-" + MAXLEN + "s -- %s",
|
||||
count, text,
|
||||
(e == null ? "null" : e.getKind() + " " + e)));
|
||||
|
||||
Messager m = processingEnv.getMessager();
|
||||
if (e == null) {
|
||||
m.printMessage(Diagnostic.Kind.ERROR, "Null element found for " + text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (last && !e.getSimpleName().contentEquals("last")) {
|
||||
m.printMessage(Diagnostic.Kind.ERROR, "Unexpected name in last test: "
|
||||
+ e.getSimpleName() + ", expected: last");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// following are all fodder for the test
|
||||
|
||||
class MemberClass {
|
||||
class NestedMemberClass { }
|
||||
}
|
||||
|
||||
{
|
||||
class InnerClassInInit { }
|
||||
Object o = new Object() { };
|
||||
}
|
||||
|
||||
TestGetElement(TestGetElement unused) {
|
||||
class InnerClassInConstr { }
|
||||
Object o = new Object() { };
|
||||
}
|
||||
|
||||
void m() {
|
||||
class InnerClassInMethod { }
|
||||
Object o = new Object() { };
|
||||
|
||||
class C {
|
||||
class MemberClass {
|
||||
class NestedMemberClass { }
|
||||
}
|
||||
|
||||
{
|
||||
class InnerClassInInit { }
|
||||
Object o = new Object() { };
|
||||
}
|
||||
|
||||
C(Object unused) {
|
||||
class InnerClassInConstr { }
|
||||
Object o = new Object() { };
|
||||
}
|
||||
|
||||
void m() {
|
||||
class InnerClassInMethod { }
|
||||
Object o = new Object() { };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int last; // this name is verified by the test to make sure that all decls are checked
|
||||
}
|
@ -27,8 +27,7 @@
|
||||
* @summary Test that reported names of anonymous classes are non-null.
|
||||
* @author Joseph D. Darcy
|
||||
* @build TestAnonSourceNames
|
||||
* @compile/fail -processor TestAnonSourceNames TestAnonClassNames.java
|
||||
* @build TestAnonClassNames
|
||||
* @compile -processor TestAnonSourceNames TestAnonClassNames.java
|
||||
* @run main TestAnonClassNames
|
||||
*/
|
||||
|
||||
@ -40,10 +39,6 @@
|
||||
*
|
||||
* Source files will be tested by the @compile line which runs
|
||||
* TestAnonSourceNames as an annotation processor over this file.
|
||||
* This compile line is expected to fail until 6930507 is fixed. Once
|
||||
* bug 6930507 is fixed, the "@compile/fail -processor ..." and
|
||||
* following "@build..." steps can be replaced with a single "@compile
|
||||
* -processor ..." directive.
|
||||
*
|
||||
* Class files are tested by the @run command on this type. This
|
||||
* class gets the names of classes with different nesting kinds,
|
||||
|
@ -67,7 +67,7 @@ public class TestAnonSourceNames extends AbstractProcessor {
|
||||
Element element = trees.getElement(trees.getPath(cu, node));
|
||||
if (element == null) {
|
||||
processingEnv.getMessager().printMessage(ERROR,
|
||||
"No element retreived for node named ''" +
|
||||
"No element retrieved for node named ''" +
|
||||
node.getSimpleName() + "''.");
|
||||
} else {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user