darcy@515: /* jjg@937: * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. darcy@515: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. darcy@515: * darcy@515: * This code is free software; you can redistribute it and/or modify it darcy@515: * under the terms of the GNU General Public License version 2 only, as darcy@515: * published by the Free Software Foundation. darcy@515: * darcy@515: * This code is distributed in the hope that it will be useful, but WITHOUT darcy@515: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or darcy@515: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License darcy@515: * version 2 for more details (a copy is included in the LICENSE file that darcy@515: * accompanied this code). darcy@515: * darcy@515: * You should have received a copy of the GNU General Public License version darcy@515: * 2 along with this work; if not, write to the Free Software Foundation, darcy@515: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. darcy@515: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. darcy@515: */ darcy@515: darcy@515: /* darcy@515: * @test jjg@937: * @bug 6449781 6930508 darcy@515: * @summary Test that reported names of anonymous classes are non-null. darcy@515: * @author Joseph D. Darcy darcy@1466: * @library /tools/javac/lib darcy@699: * @build JavacTestingAbstractProcessor TestAnonSourceNames jjg@672: * @compile -processor TestAnonSourceNames TestAnonClassNames.java darcy@515: * @run main TestAnonClassNames darcy@515: */ darcy@515: darcy@515: /* darcy@515: * This test operates in phases to test retrieving the qualified name darcy@515: * of anonymous classes from type elements modeling the anonymous darcy@515: * class. The type elements are generated using both source files and darcy@515: * class files as the basis of constructing the elements. darcy@515: * darcy@515: * Source files will be tested by the @compile line which runs darcy@515: * TestAnonSourceNames as an annotation processor over this file. darcy@515: * darcy@515: * Class files are tested by the @run command on this type. This darcy@515: * class gets the names of classes with different nesting kinds, darcy@515: * including anonymous classes, and then invokes the compiler with an darcy@515: * annotation processor having the class files names as inputs. The darcy@515: * compiler is invoked via the javax.tools mechanism. darcy@515: */ darcy@515: darcy@515: import java.lang.annotation.*; darcy@515: import javax.lang.model.element.*; darcy@515: import javax.annotation.processing.*; darcy@515: import javax.lang.model.SourceVersion; darcy@515: import javax.lang.model.element.*; darcy@515: import javax.lang.model.util.*; darcy@515: import javax.tools.*; darcy@515: import java.util.*; darcy@515: darcy@515: import static java.lang.annotation.RetentionPolicy.*; darcy@515: import static javax.lang.model.element.NestingKind.*; darcy@515: import static javax.lang.model.util.ElementFilter.*; darcy@515: import static javax.tools.Diagnostic.Kind.*; darcy@515: import static javax.tools.StandardLocation.*; darcy@515: darcy@515: @Nesting(TOP_LEVEL) darcy@515: public class TestAnonClassNames { darcy@515: @Nesting(MEMBER) darcy@515: static class MemberClass1{} darcy@515: darcy@515: @Nesting(MEMBER) darcy@515: class MemberClass2{} darcy@515: darcy@515: @Nesting(MEMBER) darcy@515: class Win$$AtVegas { } // Class with funny name. darcy@515: darcy@515: public static void main(String... argv) { darcy@515: @Nesting(LOCAL) darcy@515: class LocalClass{}; darcy@515: jjg@722: Object o = new /*@Nesting(ANONYMOUS)*/ Object() { // An anonymous annotated class darcy@515: public String toString() { darcy@515: return "I have no name!"; darcy@515: } darcy@515: }; darcy@515: darcy@515: Class[] classes = { darcy@515: MemberClass1.class, darcy@515: MemberClass2.class, darcy@515: LocalClass.class, darcy@515: Win$$AtVegas.class, darcy@515: o.getClass(), darcy@515: TestAnonClassNames.class, darcy@515: }; darcy@515: jjg@937: List names = new ArrayList(); darcy@515: for(Class clazz : classes) { darcy@515: String name = clazz.getName(); jjg@722: Nesting anno = clazz.getAnnotation(Nesting.class); darcy@515: System.out.format("%s is %s%n", darcy@515: clazz.getName(), jjg@722: anno == null ? "(unset/ANONYMOUS)" : anno.value()); darcy@515: testClassName(name); jjg@937: names.add(name); darcy@515: } jjg@937: jjg@937: // test all names together jjg@937: testClassNames(names); jjg@937: jjg@937: if (errors > 0) jjg@937: throw new RuntimeException(errors + " errors occurred"); darcy@515: } darcy@515: darcy@515: /** darcy@515: * Perform annotation processing on the class file name and verify darcy@515: * the existence of different flavors of class names when the darcy@515: * input classes are modeled as elements. darcy@515: */ darcy@515: static void testClassName(String className) { jjg@937: testClassNames(Arrays.asList(className)); jjg@937: } jjg@937: jjg@937: /** jjg@937: * Perform annotation processing on a list of class file names and verify jjg@937: * the existence of different flavors of class names when the jjg@937: * input classes are modeled as elements. jjg@937: */ jjg@937: static void testClassNames(List classNames) { jjg@937: System.out.println("test: " + classNames); darcy@515: mcimadamore@536: List options = new ArrayList(); darcy@515: options.add("-proc:only"); darcy@515: options.add("-classpath"); darcy@515: options.add(System.getProperty("test.classes")); darcy@515: jjg@937: JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); darcy@515: JavaCompiler.CompilationTask compileTask = darcy@515: javaCompiler.getTask(null, // Output darcy@515: null, // File manager darcy@515: null, // Diagnostics darcy@515: options, darcy@515: classNames, darcy@515: null); // Sources mcimadamore@536: List processors = new ArrayList(); darcy@515: processors.add(new ClassNameProber()); darcy@515: compileTask.setProcessors(processors); darcy@515: Boolean goodResult = compileTask.call(); darcy@515: if (!goodResult) { jjg@937: error("Errors found during compile."); darcy@515: } darcy@515: } jjg@937: jjg@937: static int errors = 0; jjg@937: jjg@937: static void error(String msg) { jjg@937: System.out.println("Error: " + msg); jjg@937: errors++; jjg@937: } darcy@515: } darcy@515: darcy@515: @Retention(RUNTIME) darcy@515: @interface Nesting { darcy@515: NestingKind value(); darcy@515: } darcy@515: darcy@515: /** darcy@515: * Probe at the various kinds of names of a type element. darcy@515: */ darcy@699: class ClassNameProber extends JavacTestingAbstractProcessor { darcy@515: public ClassNameProber(){super();} darcy@515: darcy@515: private boolean classesFound=false; darcy@515: darcy@515: public boolean process(Set annotations, darcy@515: RoundEnvironment roundEnv) { darcy@515: if (!roundEnv.processingOver()) { darcy@515: for(TypeElement typeElt : typesIn(roundEnv.getRootElements())) { darcy@515: classesFound = true; darcy@515: darcy@515: // Verify different names are non-null; an NPE will darcy@515: // result in failed compile status being reported. darcy@515: NestingKind nestingKind = typeElt.getNestingKind(); darcy@515: System.out.printf("\tSimple name: ''%s''\tQualified Name: ''%s''\tKind ''%s''\tNesting ''%s''%n", darcy@515: typeElt.getSimpleName().toString(), darcy@515: typeElt.getQualifiedName().toString(), darcy@515: typeElt.getKind().toString(), darcy@515: nestingKind.toString()); jjg@722: Nesting anno = typeElt.getAnnotation(Nesting.class); jjg@722: if ((anno == null ? NestingKind.ANONYMOUS : anno.value()) != nestingKind) { darcy@515: throw new RuntimeException("Mismatch of expected and reported nesting kind."); darcy@515: } darcy@515: } darcy@515: darcy@515: } darcy@515: darcy@515: if (!classesFound) { darcy@515: throw new RuntimeException("Error: no classes processed."); darcy@515: } darcy@515: return true; darcy@515: } darcy@515: }