1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/6889255/T6889255.java Mon Oct 19 13:38:09 2009 -0700 1.3 @@ -0,0 +1,485 @@ 1.4 +/* 1.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + */ 1.26 + 1.27 +/* 1.28 + * @test 1.29 + * @bug 6889255 1.30 + * @summary ClassReader does not read parameter names correctly 1.31 + */ 1.32 + 1.33 +import java.io.*; 1.34 +import java.util.*; 1.35 +import javax.tools.StandardLocation; 1.36 +import com.sun.tools.javac.code.Flags; 1.37 +import com.sun.tools.javac.code.Kinds; 1.38 +import com.sun.tools.javac.code.Scope; 1.39 +import com.sun.tools.javac.code.Symbol.*; 1.40 +import com.sun.tools.javac.code.Type; 1.41 +import com.sun.tools.javac.code.Type.ClassType; 1.42 +import com.sun.tools.javac.code.TypeTags; 1.43 +import com.sun.tools.javac.file.JavacFileManager; 1.44 +import com.sun.tools.javac.jvm.ClassReader; 1.45 +import com.sun.tools.javac.util.Context; 1.46 +import com.sun.tools.javac.util.Names; 1.47 + 1.48 +public class T6889255 { 1.49 + boolean testInterfaces = true; 1.50 + boolean testSyntheticMethods = true; 1.51 + 1.52 + // The following enums control the generation of the test methods to be compiled. 1.53 + enum GenericKind { 1.54 + NOT_GENERIC, 1.55 + GENERIC 1.56 + }; 1.57 + 1.58 + enum ClassKind { 1.59 + CLASS("Clss"), 1.60 + INTERFACE("Intf"), 1.61 + ENUM("Enum"); 1.62 + final String base; 1.63 + ClassKind(String base) { this.base = base; } 1.64 + }; 1.65 + 1.66 + enum NestedKind { 1.67 + /** Declare methods inside the outermost container. */ 1.68 + NONE, 1.69 + /** Declare methods inside a container with a 'static' modifier. */ 1.70 + NESTED, 1.71 + /** Declare methods inside a container without a 'static' modifier. */ 1.72 + INNER, 1.73 + /** Declare methods inside a local class in an initializer. */ 1.74 + INIT_LOCAL, 1.75 + /** Declare methods inside an anonymous class in an initializer. */ 1.76 + INIT_ANON, 1.77 + /** Declare methods inside a local class in a method. */ 1.78 + METHOD_LOCAL, 1.79 + /** Declare methods inside an anonymous class in a method. */ 1.80 + METHOD_ANON 1.81 + }; 1.82 + 1.83 + enum MethodKind { 1.84 + ABSTRACT, 1.85 + CONSTRUCTOR, 1.86 + METHOD, 1.87 + STATIC_METHOD, 1.88 + BRIDGE_METHOD 1.89 + }; 1.90 + 1.91 + enum FinalKind { 1.92 + /** Method body does not reference external final variables. */ 1.93 + NO_FINAL, 1.94 + /** Method body references external final variables. */ 1.95 + USE_FINAL 1.96 + }; 1.97 + 1.98 + public static void main(String... args) throws Exception { 1.99 + new T6889255().run(); 1.100 + } 1.101 + 1.102 + void run() throws Exception { 1.103 + genTest(); 1.104 + 1.105 + test("no-args", false); 1.106 + test("g", true, "-g"); 1.107 + 1.108 + if (errors > 0) 1.109 + throw new Exception(errors + " errors found"); 1.110 + } 1.111 + 1.112 + /** 1.113 + * Create a file containing lots of method definitions to be tested. 1.114 + * There are 3 sets of nested loops that generate the methods. 1.115 + * 1. The outermost set declares [generic] (class | interface | enum) 1.116 + * 2. The middle set declares [(nested | inner | anon | local)] class 1.117 + * 3. The innermost set declares 1.118 + * [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope] 1.119 + * Invalid combinations are filtered out. 1.120 + */ 1.121 + void genTest() throws Exception { 1.122 + BufferedWriter out = new BufferedWriter(new FileWriter("Test.java")); 1.123 + 1.124 + // This interface is used to force bridge methods to be generated, by 1.125 + // implementing its methods with subtypes of Object 1.126 + out.write("interface Base {\n"); 1.127 + out.write(" Object base_m1(int i1);\n"); 1.128 + out.write(" Object base_m2(int i1);\n"); 1.129 + out.write("}\n"); 1.130 + 1.131 + int outerNum = 0; 1.132 + // Outermost set of loops, to generate a top level container 1.133 + for (GenericKind outerGenericKind: GenericKind.values()) { 1.134 + for (ClassKind outerClassKind: ClassKind.values()) { 1.135 + if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM) 1.136 + continue; 1.137 + String outerClassName = outerClassKind.base + (outerNum++); 1.138 + String outerTypeArg = outerClassKind.toString().charAt(0) + "T"; 1.139 + if (outerClassKind == ClassKind.CLASS) 1.140 + out.write("abstract "); 1.141 + out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName); 1.142 + if (outerGenericKind == GenericKind.GENERIC) 1.143 + out.write("<" + outerTypeArg + ">"); 1.144 + if (outerClassKind == ClassKind.INTERFACE) 1.145 + out.write(" extends Base"); 1.146 + else 1.147 + out.write(" implements Base"); 1.148 + out.write(" {\n"); 1.149 + if (outerClassKind == ClassKind.ENUM) { 1.150 + out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n"); 1.151 + out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n"); 1.152 + } 1.153 + // Middle set of loops, to generate an optional nested container 1.154 + int nestedNum = 0; 1.155 + int methodNum = 0; 1.156 + for (GenericKind nestedGenericKind: GenericKind.values()) { 1.157 + nextNestedKind: 1.158 + for (NestedKind nestedKind: NestedKind.values()) { 1.159 + // if the nested kind is none, there is no point iterating over all 1.160 + // nested generic kinds, so arbitarily limit it to just one kind 1.161 + if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC) 1.162 + continue; 1.163 + if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON) 1.164 + && nestedGenericKind == GenericKind.GENERIC) 1.165 + continue; 1.166 + String indent = " "; 1.167 + boolean haveFinal = false; 1.168 + switch (nestedKind) { 1.169 + case METHOD_ANON: case METHOD_LOCAL: 1.170 + if (outerClassKind == ClassKind.INTERFACE) 1.171 + continue nextNestedKind; 1.172 + out.write(indent + "void m" + + (nestedNum++) + "() {\n"); 1.173 + indent += " "; 1.174 + out.write(indent + "final int fi1 = 0;\n"); 1.175 + haveFinal = true; 1.176 + break; 1.177 + case INIT_ANON: case INIT_LOCAL: 1.178 + if (outerClassKind == ClassKind.INTERFACE) 1.179 + continue nextNestedKind; 1.180 + out.write(indent + "{\n"); 1.181 + indent += " "; 1.182 + break; 1.183 + } 1.184 + for (ClassKind nestedClassKind: ClassKind.values()) { 1.185 + if ((nestedGenericKind == GenericKind.GENERIC) 1.186 + && (nestedClassKind == ClassKind.ENUM)) 1.187 + continue; 1.188 + if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL 1.189 + || nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL) 1.190 + && nestedClassKind != ClassKind.CLASS) 1.191 + continue; 1.192 + // if the nested kind is none, there is no point iterating over all 1.193 + // nested class kinds, so arbitarily limit it to just one kind 1.194 + if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS) 1.195 + continue; 1.196 + 1.197 + ClassKind methodClassKind; 1.198 + String methodClassName; 1.199 + boolean allowAbstractMethods; 1.200 + boolean allowStaticMethods; 1.201 + switch (nestedKind) { 1.202 + case NONE: 1.203 + methodClassKind = outerClassKind; 1.204 + methodClassName = outerClassName; 1.205 + allowAbstractMethods = (outerClassKind == ClassKind.CLASS); 1.206 + allowStaticMethods = (outerClassKind != ClassKind.INTERFACE); 1.207 + break; 1.208 + case METHOD_ANON: 1.209 + case INIT_ANON: 1.210 + out.write(indent + "new Base() {\n"); 1.211 + indent += " "; 1.212 + methodClassKind = ClassKind.CLASS; 1.213 + methodClassName = null; 1.214 + allowAbstractMethods = false; 1.215 + allowStaticMethods = false; 1.216 + break; 1.217 + default: { // INNER, NESTED, LOCAL 1.218 + String nestedClassName = "N" + nestedClassKind.base + (nestedNum++); 1.219 + String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T"; 1.220 + out.write(indent); 1.221 + if (nestedKind == NestedKind.NESTED) 1.222 + out.write("static "); 1.223 + if (nestedClassKind == ClassKind.CLASS) 1.224 + out.write("abstract "); 1.225 + out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName); 1.226 + if (nestedGenericKind == GenericKind.GENERIC) 1.227 + out.write("<" + nestedTypeArg + ">"); 1.228 + if (nestedClassKind == ClassKind.INTERFACE) 1.229 + out.write(" extends Base "); 1.230 + else 1.231 + out.write(" implements Base "); 1.232 + out.write(" {\n"); 1.233 + indent += " "; 1.234 + if (nestedClassKind == ClassKind.ENUM) { 1.235 + out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n"); 1.236 + out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n"); 1.237 + } 1.238 + methodClassKind = nestedClassKind; 1.239 + methodClassName = nestedClassName; 1.240 + allowAbstractMethods = (nestedClassKind == ClassKind.CLASS); 1.241 + allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE); 1.242 + break; 1.243 + } 1.244 + } 1.245 + 1.246 + // Innermost loops, to generate methods 1.247 + for (GenericKind methodGenericKind: GenericKind.values()) { 1.248 + for (FinalKind finalKind: FinalKind.values()) { 1.249 + for (MethodKind methodKind: MethodKind.values()) { 1.250 +// out.write("// " + outerGenericKind 1.251 +// + " " + outerClassKind 1.252 +// + " " + nestedKind 1.253 +// + " " + nestedGenericKind 1.254 +// + " " + nestedClassKind 1.255 +// + " " + methodGenericKind 1.256 +// + " " + finalKind 1.257 +// + " " + methodKind 1.258 +// + "\n"); 1.259 + switch (methodKind) { 1.260 + case CONSTRUCTOR: 1.261 + if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON) 1.262 + break; 1.263 + if (methodClassKind != ClassKind.CLASS) 1.264 + break; 1.265 + if (finalKind == FinalKind.USE_FINAL && !haveFinal) 1.266 + break; 1.267 + out.write(indent); 1.268 + if (methodGenericKind == GenericKind.GENERIC) { 1.269 + out.write("<CT> " + methodClassName + "(CT c1, CT c2"); 1.270 + } else { 1.271 + out.write(methodClassName + "(boolean b1, char c2"); 1.272 + } 1.273 + if (finalKind == FinalKind.USE_FINAL) { 1.274 + // add a dummy parameter to avoid duplicate declaration 1.275 + out.write(", int i3) { int i = fi1; }\n"); 1.276 + } else 1.277 + out.write(") { }\n"); 1.278 + break; 1.279 + case ABSTRACT: 1.280 + if (!allowAbstractMethods) 1.281 + continue; 1.282 + // fallthrough 1.283 + case METHOD: 1.284 + if (finalKind == FinalKind.USE_FINAL && !haveFinal) 1.285 + break; 1.286 + out.write(indent); 1.287 + if (methodKind == MethodKind.ABSTRACT) 1.288 + out.write("abstract "); 1.289 + if (methodGenericKind == GenericKind.GENERIC) 1.290 + out.write("<MT> "); 1.291 + out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)"); 1.292 + if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE) 1.293 + out.write(";\n"); 1.294 + else { 1.295 + out.write(" {"); 1.296 + if (finalKind == FinalKind.USE_FINAL) 1.297 + out.write(" int i = fi1;"); 1.298 + out.write(" }\n"); 1.299 + } 1.300 + break; 1.301 + case BRIDGE_METHOD: 1.302 + if (methodGenericKind == GenericKind.GENERIC) 1.303 + break; 1.304 + out.write(indent); 1.305 + // methods Base.base_m1 and Base.base_m2 are declared for the 1.306 + // benefit of bridge methods. They need to be implemented 1.307 + // whether or not a final variable is used. 1.308 + String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2"); 1.309 + out.write("public String " + methodName + "(int i1)"); 1.310 + if (methodClassKind == ClassKind.INTERFACE) 1.311 + out.write(";\n"); 1.312 + else { 1.313 + out.write(" {"); 1.314 + if (finalKind == FinalKind.USE_FINAL && haveFinal) 1.315 + out.write(" int i = fi1;"); 1.316 + out.write(" return null; }\n"); 1.317 + } 1.318 + break; 1.319 + case STATIC_METHOD: 1.320 + if (!allowStaticMethods) 1.321 + break; 1.322 + if (finalKind == FinalKind.USE_FINAL && !haveFinal) 1.323 + break; 1.324 + out.write(indent + "static "); 1.325 + if (methodGenericKind == GenericKind.GENERIC) 1.326 + out.write("<MT> "); 1.327 + out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {"); 1.328 + if (finalKind == FinalKind.USE_FINAL) 1.329 + out.write(" int i = fi1;"); 1.330 + out.write(" }\n"); 1.331 + break; 1.332 + } 1.333 + 1.334 + } 1.335 + } 1.336 + } 1.337 + if (nestedKind != NestedKind.NONE) { 1.338 + indent = indent.substring(0, indent.length() - 4); 1.339 + out.write(indent + "};\n"); 1.340 + } 1.341 + } 1.342 + switch (nestedKind) { 1.343 + case METHOD_ANON: case METHOD_LOCAL: 1.344 + case INIT_ANON: case INIT_LOCAL: 1.345 + indent = indent.substring(0, indent.length() - 4); 1.346 + out.write(indent + "}\n\n"); 1.347 + } 1.348 + } 1.349 + } 1.350 + out.write("}\n\n"); 1.351 + } 1.352 + } 1.353 + out.close(); 1.354 + } 1.355 + 1.356 + 1.357 + void test(String testName, boolean expectNames, String... opts) throws Exception { 1.358 + System.err.println("Test " + testName 1.359 + + ": expectNames:" + expectNames 1.360 + + " javacOpts:" + Arrays.asList(opts)); 1.361 + 1.362 + File outDir = new File(testName); 1.363 + outDir.mkdirs(); 1.364 + compile(outDir, opts); 1.365 + 1.366 + Context ctx = new Context(); 1.367 + JavacFileManager fm = new JavacFileManager(ctx, true, null); 1.368 + fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir)); 1.369 + ClassReader cr = ClassReader.instance(ctx); 1.370 + cr.saveParameterNames = true; 1.371 + Names names = Names.instance(ctx); 1.372 + 1.373 + Set<String> classes = getTopLevelClasses(outDir); 1.374 + Deque<String> work = new LinkedList<String>(classes); 1.375 + String classname; 1.376 + while ((classname = work.poll()) != null) { 1.377 + System.err.println("Checking class " + classname); 1.378 + ClassSymbol sym = cr.enterClass(names.table.fromString(classname)); 1.379 + sym.complete(); 1.380 + 1.381 + if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces) 1.382 + continue; 1.383 + 1.384 + for (Scope.Entry e = sym.members_field.elems; e != null; e = e.sibling) { 1.385 + System.err.println("Checking member " + e.sym); 1.386 + switch (e.sym.kind) { 1.387 + case Kinds.TYP: { 1.388 + String name = e.sym.flatName().toString(); 1.389 + if (!classes.contains(name)) { 1.390 + classes.add(name); 1.391 + work.add(name); 1.392 + } 1.393 + break; 1.394 + } 1.395 + case Kinds.MTH: 1.396 + verify((MethodSymbol) e.sym, expectNames); 1.397 + break; 1.398 + } 1.399 + 1.400 + } 1.401 + } 1.402 + } 1.403 + 1.404 + void verify(MethodSymbol m, boolean expectNames) { 1.405 + if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods) 1.406 + return; 1.407 + 1.408 + //System.err.println("verify: " + m.params()); 1.409 + int i = 1; 1.410 + for (VarSymbol v: m.params()) { 1.411 + String expectName; 1.412 + if (expectNames) 1.413 + expectName = getExpectedName(v, i); 1.414 + else 1.415 + expectName = "arg" + (i - 1); 1.416 + checkEqual(expectName, v.name.toString()); 1.417 + i++; 1.418 + } 1.419 + } 1.420 + 1.421 + String getExpectedName(VarSymbol v, int i) { 1.422 + // special cases: 1.423 + // synthetic method 1.424 + if (((v.owner.owner.flags() & Flags.ENUM) != 0) 1.425 + && v.owner.name.toString().equals("valueOf")) 1.426 + return "name"; 1.427 + // interfaces don't have saved names 1.428 + // -- no Code attribute for the LocalVariableTable attribute 1.429 + if ((v.owner.owner.flags() & Flags.INTERFACE) != 0) 1.430 + return "arg" + (i - 1); 1.431 + // abstract methods don't have saved names 1.432 + // -- no Code attribute for the LocalVariableTable attribute 1.433 + if ((v.owner.flags() & Flags.ABSTRACT) != 0) 1.434 + return "arg" + (i - 1); 1.435 + // bridge methods use xN 1.436 + if ((v.owner.flags() & Flags.BRIDGE) != 0) 1.437 + return "x" + (i - 1); 1.438 + 1.439 + // The rest of this method assumes the local conventions in the test program 1.440 + Type t = v.type; 1.441 + String s; 1.442 + if (t.tag == TypeTags.CLASS) 1.443 + s = ((ClassType) t).tsym.name.toString(); 1.444 + else 1.445 + s = t.toString(); 1.446 + return String.valueOf(Character.toLowerCase(s.charAt(0))) + i; 1.447 + } 1.448 + 1.449 + void compile(File outDir, String... opts) throws Exception { 1.450 + //File testSrc = new File(System.getProperty("test.src"), "."); 1.451 + List<String> args = new ArrayList<String>(); 1.452 + args.add("-d"); 1.453 + args.add(outDir.getPath()); 1.454 + args.addAll(Arrays.asList(opts)); 1.455 + //args.add(new File(testSrc, "Test.java").getPath()); 1.456 + args.add("Test.java"); 1.457 + StringWriter sw = new StringWriter(); 1.458 + PrintWriter pw = new PrintWriter(sw); 1.459 + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw); 1.460 + pw.close(); 1.461 + if (rc != 0) { 1.462 + System.err.println(sw.toString()); 1.463 + throw new Exception("compilation failed unexpectedly"); 1.464 + } 1.465 + } 1.466 + 1.467 + Set<String> getTopLevelClasses(File outDir) { 1.468 + Set<String> classes = new HashSet<String>(); 1.469 + for (String f: outDir.list()) { 1.470 + if (f.endsWith(".class") && !f.contains("$")) 1.471 + classes.add(f.replace(".class", "")); 1.472 + } 1.473 + return classes; 1.474 + } 1.475 + 1.476 + void checkEqual(String expect, String found) { 1.477 + if (!expect.equals(found)) 1.478 + error("mismatch: expected:" + expect + " found:" + found); 1.479 + } 1.480 + 1.481 + void error(String msg) { 1.482 + System.err.println(msg); 1.483 + errors++; 1.484 + throw new Error(); 1.485 + } 1.486 + 1.487 + int errors; 1.488 +}