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