Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/test/tools/javac/6889255/T6889255.java
38813 views
/*1* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 688925526* @summary ClassReader does not read parameter names correctly27*/2829import java.io.*;30import java.util.*;31import javax.tools.StandardLocation;32import com.sun.tools.javac.code.Flags;33import com.sun.tools.javac.code.Kinds;34import com.sun.tools.javac.code.Scope;35import com.sun.tools.javac.code.Symbol.*;36import com.sun.tools.javac.code.Type;37import com.sun.tools.javac.code.Type.ClassType;38import com.sun.tools.javac.code.TypeTag;39import com.sun.tools.javac.file.JavacFileManager;40import com.sun.tools.javac.jvm.ClassReader;41import com.sun.tools.javac.util.Context;42import com.sun.tools.javac.util.Names;4344public class T6889255 {45boolean testInterfaces = true;46boolean testSyntheticMethods = true;4748// The following enums control the generation of the test methods to be compiled.49enum GenericKind {50NOT_GENERIC,51GENERIC52};5354enum ClassKind {55CLASS("Clss"),56INTERFACE("Intf"),57ENUM("Enum");58final String base;59ClassKind(String base) { this.base = base; }60};6162enum NestedKind {63/** Declare methods inside the outermost container. */64NONE,65/** Declare methods inside a container with a 'static' modifier. */66NESTED,67/** Declare methods inside a container without a 'static' modifier. */68INNER,69/** Declare methods inside a local class in an initializer. */70INIT_LOCAL,71/** Declare methods inside an anonymous class in an initializer. */72INIT_ANON,73/** Declare methods inside a local class in a method. */74METHOD_LOCAL,75/** Declare methods inside an anonymous class in a method. */76METHOD_ANON77};7879enum MethodKind {80ABSTRACT,81CONSTRUCTOR,82METHOD,83STATIC_METHOD,84BRIDGE_METHOD85};8687enum FinalKind {88/** Method body does not reference external final variables. */89NO_FINAL,90/** Method body references external final variables. */91USE_FINAL92};9394public static void main(String... args) throws Exception {95new T6889255().run();96}9798void run() throws Exception {99genTest();100101test("no-args", false);102test("g", true, "-g");103104if (errors > 0)105throw new Exception(errors + " errors found");106}107108/**109* Create a file containing lots of method definitions to be tested.110* There are 3 sets of nested loops that generate the methods.111* 1. The outermost set declares [generic] (class | interface | enum)112* 2. The middle set declares [(nested | inner | anon | local)] class113* 3. The innermost set declares114* [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope]115* Invalid combinations are filtered out.116*/117void genTest() throws Exception {118BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));119120// This interface is used to force bridge methods to be generated, by121// implementing its methods with subtypes of Object122out.write("interface Base {\n");123out.write(" Object base_m1(int i1);\n");124out.write(" Object base_m2(int i1);\n");125out.write("}\n");126127int outerNum = 0;128// Outermost set of loops, to generate a top level container129for (GenericKind outerGenericKind: GenericKind.values()) {130for (ClassKind outerClassKind: ClassKind.values()) {131if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM)132continue;133String outerClassName = outerClassKind.base + (outerNum++);134String outerTypeArg = outerClassKind.toString().charAt(0) + "T";135if (outerClassKind == ClassKind.CLASS)136out.write("abstract ");137out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName);138if (outerGenericKind == GenericKind.GENERIC)139out.write("<" + outerTypeArg + ">");140if (outerClassKind == ClassKind.INTERFACE)141out.write(" extends Base");142else143out.write(" implements Base");144out.write(" {\n");145if (outerClassKind == ClassKind.ENUM) {146out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");147out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n");148}149// Middle set of loops, to generate an optional nested container150int nestedNum = 0;151int methodNum = 0;152for (GenericKind nestedGenericKind: GenericKind.values()) {153nextNestedKind:154for (NestedKind nestedKind: NestedKind.values()) {155// if the nested kind is none, there is no point iterating over all156// nested generic kinds, so arbitarily limit it to just one kind157if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC)158continue;159if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)160&& nestedGenericKind == GenericKind.GENERIC)161continue;162String indent = " ";163boolean haveFinal = false;164switch (nestedKind) {165case METHOD_ANON: case METHOD_LOCAL:166if (outerClassKind == ClassKind.INTERFACE)167continue nextNestedKind;168out.write(indent + "void m" + + (nestedNum++) + "() {\n");169indent += " ";170out.write(indent + "final int fi1 = 0;\n");171haveFinal = true;172break;173case INIT_ANON: case INIT_LOCAL:174if (outerClassKind == ClassKind.INTERFACE)175continue nextNestedKind;176out.write(indent + "{\n");177indent += " ";178break;179}180for (ClassKind nestedClassKind: ClassKind.values()) {181if ((nestedGenericKind == GenericKind.GENERIC)182&& (nestedClassKind == ClassKind.ENUM))183continue;184if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL185|| nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)186&& nestedClassKind != ClassKind.CLASS)187continue;188// if the nested kind is none, there is no point iterating over all189// nested class kinds, so arbitarily limit it to just one kind190if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS)191continue;192193ClassKind methodClassKind;194String methodClassName;195boolean allowAbstractMethods;196boolean allowStaticMethods;197switch (nestedKind) {198case NONE:199methodClassKind = outerClassKind;200methodClassName = outerClassName;201allowAbstractMethods = (outerClassKind == ClassKind.CLASS);202allowStaticMethods = (outerClassKind != ClassKind.INTERFACE);203break;204case METHOD_ANON:205case INIT_ANON:206out.write(indent + "new Base() {\n");207indent += " ";208methodClassKind = ClassKind.CLASS;209methodClassName = null;210allowAbstractMethods = false;211allowStaticMethods = false;212break;213default: { // INNER, NESTED, LOCAL214String nestedClassName = "N" + nestedClassKind.base + (nestedNum++);215String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T";216out.write(indent);217if (nestedKind == NestedKind.NESTED)218out.write("static ");219if (nestedClassKind == ClassKind.CLASS)220out.write("abstract ");221out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName);222if (nestedGenericKind == GenericKind.GENERIC)223out.write("<" + nestedTypeArg + ">");224if (nestedClassKind == ClassKind.INTERFACE)225out.write(" extends Base ");226else227out.write(" implements Base ");228out.write(" {\n");229indent += " ";230if (nestedClassKind == ClassKind.ENUM) {231out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");232out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n");233}234methodClassKind = nestedClassKind;235methodClassName = nestedClassName;236allowAbstractMethods = (nestedClassKind == ClassKind.CLASS);237allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE);238break;239}240}241242// Innermost loops, to generate methods243for (GenericKind methodGenericKind: GenericKind.values()) {244for (FinalKind finalKind: FinalKind.values()) {245for (MethodKind methodKind: MethodKind.values()) {246// out.write("// " + outerGenericKind247// + " " + outerClassKind248// + " " + nestedKind249// + " " + nestedGenericKind250// + " " + nestedClassKind251// + " " + methodGenericKind252// + " " + finalKind253// + " " + methodKind254// + "\n");255switch (methodKind) {256case CONSTRUCTOR:257if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)258break;259if (methodClassKind != ClassKind.CLASS)260break;261if (finalKind == FinalKind.USE_FINAL && !haveFinal)262break;263out.write(indent);264if (methodGenericKind == GenericKind.GENERIC) {265out.write("<CT> " + methodClassName + "(CT c1, CT c2");266} else {267out.write(methodClassName + "(boolean b1, char c2");268}269if (finalKind == FinalKind.USE_FINAL) {270// add a dummy parameter to avoid duplicate declaration271out.write(", int i3) { int i = fi1; }\n");272} else273out.write(") { }\n");274break;275case ABSTRACT:276if (!allowAbstractMethods)277continue;278// fallthrough279case METHOD:280if (finalKind == FinalKind.USE_FINAL && !haveFinal)281break;282out.write(indent);283if (methodKind == MethodKind.ABSTRACT)284out.write("abstract ");285if (methodGenericKind == GenericKind.GENERIC)286out.write("<MT> ");287out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)");288if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE)289out.write(";\n");290else {291out.write(" {");292if (finalKind == FinalKind.USE_FINAL)293out.write(" int i = fi1;");294out.write(" }\n");295}296break;297case BRIDGE_METHOD:298if (methodGenericKind == GenericKind.GENERIC)299break;300out.write(indent);301// methods Base.base_m1 and Base.base_m2 are declared for the302// benefit of bridge methods. They need to be implemented303// whether or not a final variable is used.304String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2");305out.write("public String " + methodName + "(int i1)");306if (methodClassKind == ClassKind.INTERFACE)307out.write(";\n");308else {309out.write(" {");310if (finalKind == FinalKind.USE_FINAL && haveFinal)311out.write(" int i = fi1;");312out.write(" return null; }\n");313}314break;315case STATIC_METHOD:316if (!allowStaticMethods)317break;318if (finalKind == FinalKind.USE_FINAL && !haveFinal)319break;320out.write(indent + "static ");321if (methodGenericKind == GenericKind.GENERIC)322out.write("<MT> ");323out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {");324if (finalKind == FinalKind.USE_FINAL)325out.write(" int i = fi1;");326out.write(" }\n");327break;328}329330}331}332}333if (nestedKind != NestedKind.NONE) {334indent = indent.substring(0, indent.length() - 4);335out.write(indent + "};\n");336}337}338switch (nestedKind) {339case METHOD_ANON: case METHOD_LOCAL:340case INIT_ANON: case INIT_LOCAL:341indent = indent.substring(0, indent.length() - 4);342out.write(indent + "}\n\n");343}344}345}346out.write("}\n\n");347}348}349out.close();350}351352353void test(String testName, boolean expectNames, String... opts) throws Exception {354System.err.println("Test " + testName355+ ": expectNames:" + expectNames356+ " javacOpts:" + Arrays.asList(opts));357358File outDir = new File(testName);359outDir.mkdirs();360compile(outDir, opts);361362Context ctx = new Context();363JavacFileManager fm = new JavacFileManager(ctx, true, null);364fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));365ClassReader cr = ClassReader.instance(ctx);366cr.saveParameterNames = true;367Names names = Names.instance(ctx);368369Set<String> classes = getTopLevelClasses(outDir);370Deque<String> work = new LinkedList<String>(classes);371String classname;372while ((classname = work.poll()) != null) {373System.err.println("Checking class " + classname);374ClassSymbol sym = cr.enterClass(names.table.fromString(classname));375sym.complete();376377if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces)378continue;379380for (Scope.Entry e = sym.members_field.elems; e != null; e = e.sibling) {381System.err.println("Checking member " + e.sym);382switch (e.sym.kind) {383case Kinds.TYP: {384String name = e.sym.flatName().toString();385if (!classes.contains(name)) {386classes.add(name);387work.add(name);388}389break;390}391case Kinds.MTH:392verify((MethodSymbol) e.sym, expectNames);393break;394}395396}397}398}399400void verify(MethodSymbol m, boolean expectNames) {401if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods)402return;403404//System.err.println("verify: " + m.params());405int i = 1;406for (VarSymbol v: m.params()) {407String expectName;408if (expectNames)409expectName = getExpectedName(v, i);410else411expectName = "arg" + (i - 1);412checkEqual(expectName, v.name.toString());413i++;414}415}416417String getExpectedName(VarSymbol v, int i) {418// special cases:419// synthetic method420if (((v.owner.owner.flags() & Flags.ENUM) != 0)421&& v.owner.name.toString().equals("valueOf"))422return "name";423// interfaces don't have saved names424// -- no Code attribute for the LocalVariableTable attribute425if ((v.owner.owner.flags() & Flags.INTERFACE) != 0)426return "arg" + (i - 1);427// abstract methods don't have saved names428// -- no Code attribute for the LocalVariableTable attribute429if ((v.owner.flags() & Flags.ABSTRACT) != 0)430return "arg" + (i - 1);431// bridge methods use argN. No LVT for them anymore432if ((v.owner.flags() & Flags.BRIDGE) != 0)433return "arg" + (i - 1);434435// The rest of this method assumes the local conventions in the test program436Type t = v.type;437String s;438if (t.hasTag(TypeTag.CLASS))439s = ((ClassType) t).tsym.name.toString();440else441s = t.toString();442return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;443}444445void compile(File outDir, String... opts) throws Exception {446//File testSrc = new File(System.getProperty("test.src"), ".");447List<String> args = new ArrayList<String>();448args.add("-d");449args.add(outDir.getPath());450args.addAll(Arrays.asList(opts));451//args.add(new File(testSrc, "Test.java").getPath());452args.add("Test.java");453StringWriter sw = new StringWriter();454PrintWriter pw = new PrintWriter(sw);455int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);456pw.close();457if (rc != 0) {458System.err.println(sw.toString());459throw new Exception("compilation failed unexpectedly");460}461}462463Set<String> getTopLevelClasses(File outDir) {464Set<String> classes = new HashSet<String>();465for (String f: outDir.list()) {466if (f.endsWith(".class") && !f.contains("$"))467classes.add(f.replace(".class", ""));468}469return classes;470}471472void checkEqual(String expect, String found) {473if (!expect.equals(found))474error("mismatch: expected:" + expect + " found:" + found);475}476477void error(String msg) {478System.err.println(msg);479errors++;480throw new Error();481}482483int errors;484}485486487