test/tools/javac/6889255/T6889255.java

changeset 428
2485f5641ed0
child 554
9d9f26857129
equal deleted inserted replaced
427:6ba399eff2cb 428:2485f5641ed0
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24 /*
25 * @test
26 * @bug 6889255
27 * @summary ClassReader does not read parameter names correctly
28 */
29
30 import java.io.*;
31 import java.util.*;
32 import javax.tools.StandardLocation;
33 import com.sun.tools.javac.code.Flags;
34 import com.sun.tools.javac.code.Kinds;
35 import com.sun.tools.javac.code.Scope;
36 import com.sun.tools.javac.code.Symbol.*;
37 import com.sun.tools.javac.code.Type;
38 import com.sun.tools.javac.code.Type.ClassType;
39 import com.sun.tools.javac.code.TypeTags;
40 import com.sun.tools.javac.file.JavacFileManager;
41 import com.sun.tools.javac.jvm.ClassReader;
42 import com.sun.tools.javac.util.Context;
43 import com.sun.tools.javac.util.Names;
44
45 public class T6889255 {
46 boolean testInterfaces = true;
47 boolean testSyntheticMethods = true;
48
49 // The following enums control the generation of the test methods to be compiled.
50 enum GenericKind {
51 NOT_GENERIC,
52 GENERIC
53 };
54
55 enum ClassKind {
56 CLASS("Clss"),
57 INTERFACE("Intf"),
58 ENUM("Enum");
59 final String base;
60 ClassKind(String base) { this.base = base; }
61 };
62
63 enum NestedKind {
64 /** Declare methods inside the outermost container. */
65 NONE,
66 /** Declare methods inside a container with a 'static' modifier. */
67 NESTED,
68 /** Declare methods inside a container without a 'static' modifier. */
69 INNER,
70 /** Declare methods inside a local class in an initializer. */
71 INIT_LOCAL,
72 /** Declare methods inside an anonymous class in an initializer. */
73 INIT_ANON,
74 /** Declare methods inside a local class in a method. */
75 METHOD_LOCAL,
76 /** Declare methods inside an anonymous class in a method. */
77 METHOD_ANON
78 };
79
80 enum MethodKind {
81 ABSTRACT,
82 CONSTRUCTOR,
83 METHOD,
84 STATIC_METHOD,
85 BRIDGE_METHOD
86 };
87
88 enum FinalKind {
89 /** Method body does not reference external final variables. */
90 NO_FINAL,
91 /** Method body references external final variables. */
92 USE_FINAL
93 };
94
95 public static void main(String... args) throws Exception {
96 new T6889255().run();
97 }
98
99 void run() throws Exception {
100 genTest();
101
102 test("no-args", false);
103 test("g", true, "-g");
104
105 if (errors > 0)
106 throw new Exception(errors + " errors found");
107 }
108
109 /**
110 * Create a file containing lots of method definitions to be tested.
111 * There are 3 sets of nested loops that generate the methods.
112 * 1. The outermost set declares [generic] (class | interface | enum)
113 * 2. The middle set declares [(nested | inner | anon | local)] class
114 * 3. The innermost set declares
115 * [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope]
116 * Invalid combinations are filtered out.
117 */
118 void genTest() throws Exception {
119 BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));
120
121 // This interface is used to force bridge methods to be generated, by
122 // implementing its methods with subtypes of Object
123 out.write("interface Base {\n");
124 out.write(" Object base_m1(int i1);\n");
125 out.write(" Object base_m2(int i1);\n");
126 out.write("}\n");
127
128 int outerNum = 0;
129 // Outermost set of loops, to generate a top level container
130 for (GenericKind outerGenericKind: GenericKind.values()) {
131 for (ClassKind outerClassKind: ClassKind.values()) {
132 if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM)
133 continue;
134 String outerClassName = outerClassKind.base + (outerNum++);
135 String outerTypeArg = outerClassKind.toString().charAt(0) + "T";
136 if (outerClassKind == ClassKind.CLASS)
137 out.write("abstract ");
138 out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName);
139 if (outerGenericKind == GenericKind.GENERIC)
140 out.write("<" + outerTypeArg + ">");
141 if (outerClassKind == ClassKind.INTERFACE)
142 out.write(" extends Base");
143 else
144 out.write(" implements Base");
145 out.write(" {\n");
146 if (outerClassKind == ClassKind.ENUM) {
147 out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
148 out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n");
149 }
150 // Middle set of loops, to generate an optional nested container
151 int nestedNum = 0;
152 int methodNum = 0;
153 for (GenericKind nestedGenericKind: GenericKind.values()) {
154 nextNestedKind:
155 for (NestedKind nestedKind: NestedKind.values()) {
156 // if the nested kind is none, there is no point iterating over all
157 // nested generic kinds, so arbitarily limit it to just one kind
158 if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC)
159 continue;
160 if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
161 && nestedGenericKind == GenericKind.GENERIC)
162 continue;
163 String indent = " ";
164 boolean haveFinal = false;
165 switch (nestedKind) {
166 case METHOD_ANON: case METHOD_LOCAL:
167 if (outerClassKind == ClassKind.INTERFACE)
168 continue nextNestedKind;
169 out.write(indent + "void m" + + (nestedNum++) + "() {\n");
170 indent += " ";
171 out.write(indent + "final int fi1 = 0;\n");
172 haveFinal = true;
173 break;
174 case INIT_ANON: case INIT_LOCAL:
175 if (outerClassKind == ClassKind.INTERFACE)
176 continue nextNestedKind;
177 out.write(indent + "{\n");
178 indent += " ";
179 break;
180 }
181 for (ClassKind nestedClassKind: ClassKind.values()) {
182 if ((nestedGenericKind == GenericKind.GENERIC)
183 && (nestedClassKind == ClassKind.ENUM))
184 continue;
185 if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL
186 || nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)
187 && nestedClassKind != ClassKind.CLASS)
188 continue;
189 // if the nested kind is none, there is no point iterating over all
190 // nested class kinds, so arbitarily limit it to just one kind
191 if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS)
192 continue;
193
194 ClassKind methodClassKind;
195 String methodClassName;
196 boolean allowAbstractMethods;
197 boolean allowStaticMethods;
198 switch (nestedKind) {
199 case NONE:
200 methodClassKind = outerClassKind;
201 methodClassName = outerClassName;
202 allowAbstractMethods = (outerClassKind == ClassKind.CLASS);
203 allowStaticMethods = (outerClassKind != ClassKind.INTERFACE);
204 break;
205 case METHOD_ANON:
206 case INIT_ANON:
207 out.write(indent + "new Base() {\n");
208 indent += " ";
209 methodClassKind = ClassKind.CLASS;
210 methodClassName = null;
211 allowAbstractMethods = false;
212 allowStaticMethods = false;
213 break;
214 default: { // INNER, NESTED, LOCAL
215 String nestedClassName = "N" + nestedClassKind.base + (nestedNum++);
216 String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T";
217 out.write(indent);
218 if (nestedKind == NestedKind.NESTED)
219 out.write("static ");
220 if (nestedClassKind == ClassKind.CLASS)
221 out.write("abstract ");
222 out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName);
223 if (nestedGenericKind == GenericKind.GENERIC)
224 out.write("<" + nestedTypeArg + ">");
225 if (nestedClassKind == ClassKind.INTERFACE)
226 out.write(" extends Base ");
227 else
228 out.write(" implements Base ");
229 out.write(" {\n");
230 indent += " ";
231 if (nestedClassKind == ClassKind.ENUM) {
232 out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
233 out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n");
234 }
235 methodClassKind = nestedClassKind;
236 methodClassName = nestedClassName;
237 allowAbstractMethods = (nestedClassKind == ClassKind.CLASS);
238 allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE);
239 break;
240 }
241 }
242
243 // Innermost loops, to generate methods
244 for (GenericKind methodGenericKind: GenericKind.values()) {
245 for (FinalKind finalKind: FinalKind.values()) {
246 for (MethodKind methodKind: MethodKind.values()) {
247 // out.write("// " + outerGenericKind
248 // + " " + outerClassKind
249 // + " " + nestedKind
250 // + " " + nestedGenericKind
251 // + " " + nestedClassKind
252 // + " " + methodGenericKind
253 // + " " + finalKind
254 // + " " + methodKind
255 // + "\n");
256 switch (methodKind) {
257 case CONSTRUCTOR:
258 if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
259 break;
260 if (methodClassKind != ClassKind.CLASS)
261 break;
262 if (finalKind == FinalKind.USE_FINAL && !haveFinal)
263 break;
264 out.write(indent);
265 if (methodGenericKind == GenericKind.GENERIC) {
266 out.write("<CT> " + methodClassName + "(CT c1, CT c2");
267 } else {
268 out.write(methodClassName + "(boolean b1, char c2");
269 }
270 if (finalKind == FinalKind.USE_FINAL) {
271 // add a dummy parameter to avoid duplicate declaration
272 out.write(", int i3) { int i = fi1; }\n");
273 } else
274 out.write(") { }\n");
275 break;
276 case ABSTRACT:
277 if (!allowAbstractMethods)
278 continue;
279 // fallthrough
280 case METHOD:
281 if (finalKind == FinalKind.USE_FINAL && !haveFinal)
282 break;
283 out.write(indent);
284 if (methodKind == MethodKind.ABSTRACT)
285 out.write("abstract ");
286 if (methodGenericKind == GenericKind.GENERIC)
287 out.write("<MT> ");
288 out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)");
289 if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE)
290 out.write(";\n");
291 else {
292 out.write(" {");
293 if (finalKind == FinalKind.USE_FINAL)
294 out.write(" int i = fi1;");
295 out.write(" }\n");
296 }
297 break;
298 case BRIDGE_METHOD:
299 if (methodGenericKind == GenericKind.GENERIC)
300 break;
301 out.write(indent);
302 // methods Base.base_m1 and Base.base_m2 are declared for the
303 // benefit of bridge methods. They need to be implemented
304 // whether or not a final variable is used.
305 String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2");
306 out.write("public String " + methodName + "(int i1)");
307 if (methodClassKind == ClassKind.INTERFACE)
308 out.write(";\n");
309 else {
310 out.write(" {");
311 if (finalKind == FinalKind.USE_FINAL && haveFinal)
312 out.write(" int i = fi1;");
313 out.write(" return null; }\n");
314 }
315 break;
316 case STATIC_METHOD:
317 if (!allowStaticMethods)
318 break;
319 if (finalKind == FinalKind.USE_FINAL && !haveFinal)
320 break;
321 out.write(indent + "static ");
322 if (methodGenericKind == GenericKind.GENERIC)
323 out.write("<MT> ");
324 out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {");
325 if (finalKind == FinalKind.USE_FINAL)
326 out.write(" int i = fi1;");
327 out.write(" }\n");
328 break;
329 }
330
331 }
332 }
333 }
334 if (nestedKind != NestedKind.NONE) {
335 indent = indent.substring(0, indent.length() - 4);
336 out.write(indent + "};\n");
337 }
338 }
339 switch (nestedKind) {
340 case METHOD_ANON: case METHOD_LOCAL:
341 case INIT_ANON: case INIT_LOCAL:
342 indent = indent.substring(0, indent.length() - 4);
343 out.write(indent + "}\n\n");
344 }
345 }
346 }
347 out.write("}\n\n");
348 }
349 }
350 out.close();
351 }
352
353
354 void test(String testName, boolean expectNames, String... opts) throws Exception {
355 System.err.println("Test " + testName
356 + ": expectNames:" + expectNames
357 + " javacOpts:" + Arrays.asList(opts));
358
359 File outDir = new File(testName);
360 outDir.mkdirs();
361 compile(outDir, opts);
362
363 Context ctx = new Context();
364 JavacFileManager fm = new JavacFileManager(ctx, true, null);
365 fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));
366 ClassReader cr = ClassReader.instance(ctx);
367 cr.saveParameterNames = true;
368 Names names = Names.instance(ctx);
369
370 Set<String> classes = getTopLevelClasses(outDir);
371 Deque<String> work = new LinkedList<String>(classes);
372 String classname;
373 while ((classname = work.poll()) != null) {
374 System.err.println("Checking class " + classname);
375 ClassSymbol sym = cr.enterClass(names.table.fromString(classname));
376 sym.complete();
377
378 if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces)
379 continue;
380
381 for (Scope.Entry e = sym.members_field.elems; e != null; e = e.sibling) {
382 System.err.println("Checking member " + e.sym);
383 switch (e.sym.kind) {
384 case Kinds.TYP: {
385 String name = e.sym.flatName().toString();
386 if (!classes.contains(name)) {
387 classes.add(name);
388 work.add(name);
389 }
390 break;
391 }
392 case Kinds.MTH:
393 verify((MethodSymbol) e.sym, expectNames);
394 break;
395 }
396
397 }
398 }
399 }
400
401 void verify(MethodSymbol m, boolean expectNames) {
402 if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods)
403 return;
404
405 //System.err.println("verify: " + m.params());
406 int i = 1;
407 for (VarSymbol v: m.params()) {
408 String expectName;
409 if (expectNames)
410 expectName = getExpectedName(v, i);
411 else
412 expectName = "arg" + (i - 1);
413 checkEqual(expectName, v.name.toString());
414 i++;
415 }
416 }
417
418 String getExpectedName(VarSymbol v, int i) {
419 // special cases:
420 // synthetic method
421 if (((v.owner.owner.flags() & Flags.ENUM) != 0)
422 && v.owner.name.toString().equals("valueOf"))
423 return "name";
424 // interfaces don't have saved names
425 // -- no Code attribute for the LocalVariableTable attribute
426 if ((v.owner.owner.flags() & Flags.INTERFACE) != 0)
427 return "arg" + (i - 1);
428 // abstract methods don't have saved names
429 // -- no Code attribute for the LocalVariableTable attribute
430 if ((v.owner.flags() & Flags.ABSTRACT) != 0)
431 return "arg" + (i - 1);
432 // bridge methods use xN
433 if ((v.owner.flags() & Flags.BRIDGE) != 0)
434 return "x" + (i - 1);
435
436 // The rest of this method assumes the local conventions in the test program
437 Type t = v.type;
438 String s;
439 if (t.tag == TypeTags.CLASS)
440 s = ((ClassType) t).tsym.name.toString();
441 else
442 s = t.toString();
443 return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;
444 }
445
446 void compile(File outDir, String... opts) throws Exception {
447 //File testSrc = new File(System.getProperty("test.src"), ".");
448 List<String> args = new ArrayList<String>();
449 args.add("-d");
450 args.add(outDir.getPath());
451 args.addAll(Arrays.asList(opts));
452 //args.add(new File(testSrc, "Test.java").getPath());
453 args.add("Test.java");
454 StringWriter sw = new StringWriter();
455 PrintWriter pw = new PrintWriter(sw);
456 int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
457 pw.close();
458 if (rc != 0) {
459 System.err.println(sw.toString());
460 throw new Exception("compilation failed unexpectedly");
461 }
462 }
463
464 Set<String> getTopLevelClasses(File outDir) {
465 Set<String> classes = new HashSet<String>();
466 for (String f: outDir.list()) {
467 if (f.endsWith(".class") && !f.contains("$"))
468 classes.add(f.replace(".class", ""));
469 }
470 return classes;
471 }
472
473 void checkEqual(String expect, String found) {
474 if (!expect.equals(found))
475 error("mismatch: expected:" + expect + " found:" + found);
476 }
477
478 void error(String msg) {
479 System.err.println(msg);
480 errors++;
481 throw new Error();
482 }
483
484 int errors;
485 }

mercurial