/* * Copyright (c) 2009, 2015, 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.
*/
enum NestedKind { /** Declare methods inside the outermost container. */
NONE, /** Declare methods inside a container with a 'static' modifier. */
NESTED, /** Declare methods inside a container without a 'static' modifier. */
INNER, /** Declare methods inside a local class in an initializer. */
INIT_LOCAL, /** Declare methods inside an anonymous class in an initializer. */
INIT_ANON, /** Declare methods inside a local class in a method. */
METHOD_LOCAL, /** Declare methods inside an anonymous class in a method. */
METHOD_ANON
};
enum FinalKind { /** Method body does not reference external final variables. */
NO_FINAL, /** Method body references external final variables. */
USE_FINAL
};
publicstaticvoid main(String... args) throws Exception { new T6889255().run();
}
/** * Create a file containing lots of method definitions to be tested. * There are 3 sets of nested loops that generate the methods. * 1. The outermost set declares [generic] (class | interface | enum) * 2. The middle set declares [(nested | inner | anon | local)] class * 3. The innermost set declares * [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope] * Invalid combinations are filtered out.
*/ void genTest() throws Exception {
BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));
// This interface is used to force bridge methods to be generated, by // implementing its methods with subtypes of Object
out.write("interface Base {\n");
out.write(" Object base_m1(int i1);\n");
out.write(" Object base_m2(int i1);\n");
out.write("}\n");
int outerNum = 0; // Outermost set of loops, to generate a top level container for (GenericKind outerGenericKind: GenericKind.values()) { for (ClassKind outerClassKind: ClassKind.values()) { if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM) continue;
String outerClassName = outerClassKind.base + (outerNum++);
String outerTypeArg = outerClassKind.toString().charAt(0) + "T"; if (outerClassKind == ClassKind.CLASS)
out.write("abstract ");
out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName); if (outerGenericKind == GenericKind.GENERIC)
out.write("<" + outerTypeArg + ">"); if (outerClassKind == ClassKind.INTERFACE)
out.write(" extends Base"); else
out.write(" implements Base");
out.write(" {\n"); if (outerClassKind == ClassKind.ENUM) {
out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n");
} // Middle set of loops, to generate an optional nested container int nestedNum = 0; int methodNum = 0; for (GenericKind nestedGenericKind: GenericKind.values()) {
nextNestedKind: for (NestedKind nestedKind: NestedKind.values()) { // if the nested kind is none, there is no point iterating over all // nested generic kinds, so arbitarily limit it to just one kind if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC) continue; if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
&& nestedGenericKind == GenericKind.GENERIC) continue;
String indent = " "; boolean haveFinal = false; switch (nestedKind) { case METHOD_ANON: case METHOD_LOCAL: if (outerClassKind == ClassKind.INTERFACE) continue nextNestedKind;
out.write(indent + "void m" + + (nestedNum++) + "() {\n");
indent += " ";
out.write(indent + "final int fi1 = 0;\n");
haveFinal = true; break; case INIT_ANON: case INIT_LOCAL: if (outerClassKind == ClassKind.INTERFACE) continue nextNestedKind;
out.write(indent + "{\n");
indent += " "; break;
} for (ClassKind nestedClassKind: ClassKind.values()) { if ((nestedGenericKind == GenericKind.GENERIC)
&& (nestedClassKind == ClassKind.ENUM)) continue; if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL
|| nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)
&& nestedClassKind != ClassKind.CLASS) continue; // if the nested kind is none, there is no point iterating over all // nested class kinds, so arbitarily limit it to just one kind if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS) continue;
File outDir = new File(testName);
outDir.mkdirs();
compile(outDir, opts);
Context ctx = new Context();
JavacFileManager fm = new JavacFileManager(ctx, true, null);
fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));
Symtab syms = Symtab.instance(ctx);
ClassReader cr = ClassReader.instance(ctx);
cr.saveParameterNames = true;
Names names = Names.instance(ctx);
Set<String> classes = getTopLevelClasses(outDir);
Deque<String> work = new LinkedList<String>(classes);
String classname; while ((classname = work.poll()) != null) {
System.err.println("Checking class " + classname);
ClassSymbol sym = syms.enterClass(syms.noModule, names.table.fromString(classname));
sym.complete();
if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces) continue;
for (Symbol s : sym.members_field.getSymbols(NON_RECURSIVE)) {
System.err.println("Checking member " + s); switch (s.kind) { case TYP: {
String name = s.flatName().toString(); if (!classes.contains(name)) {
classes.add(name);
work.add(name);
} break;
} case MTH:
verify((MethodSymbol) s, expectNames); break;
}
}
}
}
void verify(MethodSymbol m, boolean expectNames) { if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods) return;
//System.err.println("verify: " + m.params()); int i = 1; for (VarSymbol v: m.params()) {
String expectName; if (expectNames)
expectName = getExpectedName(v, i); else
expectName = "arg" + (i - 1);
checkEqual(expectName, v.name.toString());
i++;
}
}
String getExpectedName(VarSymbol v, int i) { // special cases: // synthetic method if (((v.owner.owner.flags() & Flags.ENUM) != 0)
&& v.owner.name.toString().equals("valueOf")) return"name"; // interfaces don't have saved names // -- no Code attribute for the LocalVariableTable attribute if ((v.owner.owner.flags() & Flags.INTERFACE) != 0) return"arg" + (i - 1); // abstract methods don't have saved names // -- no Code attribute for the LocalVariableTable attribute if ((v.owner.flags() & Flags.ABSTRACT) != 0) return"arg" + (i - 1); // bridge methods use argN. No LVT for them anymore if ((v.owner.flags() & Flags.BRIDGE) != 0) return"arg" + (i - 1);
// The rest of this method assumes the local conventions in the test program
Type t = v.type;
String s; if (t.hasTag(TypeTag.CLASS))
s = ((ClassType) t).tsym.name.toString(); else
s = t.toString(); return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;
}
void compile(File outDir, String... opts) throws Exception { //File testSrc = new File(System.getProperty("test.src"), ".");
List<String> args = new ArrayList<String>();
args.add("-d");
args.add(outDir.getPath());
args.addAll(Arrays.asList(opts)); //args.add(new File(testSrc, "Test.java").getPath());
args.add("Test.java");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw); int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
pw.close(); if (rc != 0) {
System.err.println(sw.toString()); thrownew Exception("compilation failed unexpectedly");
}
}
Set<String> getTopLevelClasses(File outDir) {
Set<String> classes = new HashSet<String>(); for (String f: outDir.list()) { if (f.endsWith(".class") && !f.contains("$"))
classes.add(f.replace(".class", ""));
} return classes;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.