test/tools/javac/varargs/7042566/T7042566.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
equal deleted inserted replaced
-1:000000000000 0:959103a6100f
1 /*
2 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @bug 7042566 8006694
27 * @summary Unambiguous varargs method calls flagged as ambiguous
28 * temporarily workaround combo tests are causing time out in several platforms
29 * @library ../../lib
30 * @build JavacTestingAbstractThreadedTest
31 * @run main/othervm T7042566
32 */
33
34 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
35 // see JDK-8006746
36
37 import java.io.File;
38 import java.net.URI;
39 import java.util.Arrays;
40 import java.util.Locale;
41 import java.util.concurrent.atomic.AtomicInteger;
42 import javax.tools.Diagnostic;
43 import javax.tools.JavaCompiler;
44 import javax.tools.JavaFileObject;
45 import javax.tools.SimpleJavaFileObject;
46 import javax.tools.ToolProvider;
47
48 import com.sun.source.util.JavacTask;
49 import com.sun.tools.classfile.Instruction;
50 import com.sun.tools.classfile.Attribute;
51 import com.sun.tools.classfile.ClassFile;
52 import com.sun.tools.classfile.Code_attribute;
53 import com.sun.tools.classfile.ConstantPool.*;
54 import com.sun.tools.classfile.Method;
55 import com.sun.tools.javac.util.List;
56
57 public class T7042566
58 extends JavacTestingAbstractThreadedTest
59 implements Runnable {
60
61 VarargsMethod m1;
62 VarargsMethod m2;
63 TypeConfiguration actuals;
64
65 T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf,
66 TypeConfiguration actuals) {
67 this.m1 = new VarargsMethod(m1_conf);
68 this.m2 = new VarargsMethod(m2_conf);
69 this.actuals = actuals;
70 }
71
72 @Override
73 public void run() {
74 int id = checkCount.incrementAndGet();
75 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
76 JavaSource source = new JavaSource(id);
77 ErrorChecker ec = new ErrorChecker();
78 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), ec,
79 null, null, Arrays.asList(source));
80 ct.call();
81 check(source, ec, id);
82 }
83
84 void check(JavaSource source, ErrorChecker ec, int id) {
85 boolean resolutionError = false;
86 VarargsMethod selectedMethod = null;
87
88 boolean m1_applicable = m1.isApplicable(actuals);
89 boolean m2_applicable = m2.isApplicable(actuals);
90
91 if (!m1_applicable && !m2_applicable) {
92 resolutionError = true;
93 } else if (m1_applicable && m2_applicable) {
94 //most specific
95 boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
96 boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
97
98 resolutionError = m1_moreSpecific == m2_moreSpecific;
99 selectedMethod = m1_moreSpecific ? m1 : m2;
100 } else {
101 selectedMethod = m1_applicable ?
102 m1 : m2;
103 }
104
105 if (ec.errorFound != resolutionError) {
106 throw new Error("invalid diagnostics for source:\n" +
107 source.getCharContent(true) +
108 "\nExpected resolution error: " + resolutionError +
109 "\nFound error: " + ec.errorFound +
110 "\nCompiler diagnostics:\n" + ec.printDiags());
111 } else if (!resolutionError) {
112 verifyBytecode(selectedMethod, source, id);
113 }
114 }
115
116 void verifyBytecode(VarargsMethod selected, JavaSource source, int id) {
117 bytecodeCheckCount.incrementAndGet();
118 File compiledTest = new File(String.format("Test%d.class", id));
119 try {
120 ClassFile cf = ClassFile.read(compiledTest);
121 Method testMethod = null;
122 for (Method m : cf.methods) {
123 if (m.getName(cf.constant_pool).equals("test")) {
124 testMethod = m;
125 break;
126 }
127 }
128 if (testMethod == null) {
129 throw new Error("Test method not found");
130 }
131 Code_attribute ea =
132 (Code_attribute)testMethod.attributes.get(Attribute.Code);
133 if (testMethod == null) {
134 throw new Error("Code attribute for test() method not found");
135 }
136
137 for (Instruction i : ea.getInstructions()) {
138 if (i.getMnemonic().equals("invokevirtual")) {
139 int cp_entry = i.getUnsignedShort(1);
140 CONSTANT_Methodref_info methRef =
141 (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
142 String type = methRef.getNameAndTypeInfo().getType();
143 String sig = selected.parameterTypes.bytecodeSigStr;
144 if (!type.contains(sig)) {
145 throw new Error("Unexpected type method call: " +
146 type + "" +
147 "\nfound: " + sig +
148 "\n" + source.getCharContent(true));
149 }
150 break;
151 }
152 }
153 } catch (Exception e) {
154 e.printStackTrace();
155 throw new Error("error reading " + compiledTest +": " + e);
156 }
157 }
158
159 class JavaSource extends SimpleJavaFileObject {
160
161 static final String source_template = "class Test#ID {\n" +
162 " #V1\n" +
163 " #V2\n" +
164 " void test() { m(#E); }\n" +
165 "}";
166
167 String source;
168
169 public JavaSource(int id) {
170 super(URI.create(String.format("myfo:/Test%d.java", id)),
171 JavaFileObject.Kind.SOURCE);
172 source = source_template.replaceAll("#V1", m1.toString())
173 .replaceAll("#V2", m2.toString())
174 .replaceAll("#E", actuals.expressionListStr)
175 .replaceAll("#ID", String.valueOf(id));
176 }
177
178 @Override
179 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
180 return source;
181 }
182 }
183
184 public static void main(String... args) throws Exception {
185 for (TypeConfiguration tconf1 : TypeConfiguration.values()) {
186 for (TypeConfiguration tconf2 : TypeConfiguration.values()) {
187 for (TypeConfiguration tconf3 : TypeConfiguration.values()) {
188 pool.execute(new T7042566(tconf1, tconf2, tconf3));
189 }
190 }
191 }
192
193 outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get());
194 checkAfterExec();
195 }
196
197 enum TypeKind {
198 OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
199 STRING("String", "(String)null", "Ljava/lang/String;");
200
201 String typeString;
202 String valueString;
203 String bytecodeString;
204
205 TypeKind(String typeString, String valueString, String bytecodeString) {
206 this.typeString = typeString;
207 this.valueString = valueString;
208 this.bytecodeString = bytecodeString;
209 }
210
211 boolean isSubtypeOf(TypeKind that) {
212 return that == OBJECT ||
213 (that == STRING && this == STRING);
214 }
215 }
216
217 enum TypeConfiguration {
218 A(TypeKind.OBJECT),
219 B(TypeKind.STRING),
220 AA(TypeKind.OBJECT, TypeKind.OBJECT),
221 AB(TypeKind.OBJECT, TypeKind.STRING),
222 BA(TypeKind.STRING, TypeKind.OBJECT),
223 BB(TypeKind.STRING, TypeKind.STRING),
224 AAA(TypeKind.OBJECT, TypeKind.OBJECT, TypeKind.OBJECT),
225 AAB(TypeKind.OBJECT, TypeKind.OBJECT, TypeKind.STRING),
226 ABA(TypeKind.OBJECT, TypeKind.STRING, TypeKind.OBJECT),
227 ABB(TypeKind.OBJECT, TypeKind.STRING, TypeKind.STRING),
228 BAA(TypeKind.STRING, TypeKind.OBJECT, TypeKind.OBJECT),
229 BAB(TypeKind.STRING, TypeKind.OBJECT, TypeKind.STRING),
230 BBA(TypeKind.STRING, TypeKind.STRING, TypeKind.OBJECT),
231 BBB(TypeKind.STRING, TypeKind.STRING, TypeKind.STRING);
232
233 List<TypeKind> typeKindList;
234 String expressionListStr;
235 String parameterListStr;
236 String bytecodeSigStr;
237
238 private TypeConfiguration(TypeKind... typeKindList) {
239 this.typeKindList = List.from(typeKindList);
240 expressionListStr = asExpressionList();
241 parameterListStr = asParameterList();
242 bytecodeSigStr = asBytecodeString();
243 }
244
245 private String asExpressionList() {
246 StringBuilder buf = new StringBuilder();
247 String sep = "";
248 for (TypeKind tk : typeKindList) {
249 buf.append(sep);
250 buf.append(tk.valueString);
251 sep = ",";
252 }
253 return buf.toString();
254 }
255
256 private String asParameterList() {
257 StringBuilder buf = new StringBuilder();
258 String sep = "";
259 int count = 0;
260 for (TypeKind arg : typeKindList) {
261 buf.append(sep);
262 buf.append(arg.typeString);
263 if (count == (typeKindList.size() - 1)) {
264 buf.append("...");
265 }
266 buf.append(" ");
267 buf.append("arg" + count++);
268 sep = ",";
269 }
270 return buf.toString();
271 }
272
273 private String asBytecodeString() {
274 StringBuilder buf = new StringBuilder();
275 int count = 0;
276 for (TypeKind arg : typeKindList) {
277 if (count == (typeKindList.size() - 1)) {
278 buf.append("[");
279 }
280 buf.append(arg.bytecodeString);
281 count++;
282 }
283 return buf.toString();
284 }
285 }
286
287 static class VarargsMethod {
288 TypeConfiguration parameterTypes;
289
290 public VarargsMethod(TypeConfiguration parameterTypes) {
291 this.parameterTypes = parameterTypes;
292 }
293
294 @Override
295 public String toString() {
296 return "void m( " + parameterTypes.parameterListStr + ") {}";
297 }
298
299 boolean isApplicable(TypeConfiguration that) {
300 List<TypeKind> actuals = that.typeKindList;
301 List<TypeKind> formals = parameterTypes.typeKindList;
302 if ((actuals.size() - formals.size()) < -1)
303 return false; //not enough args
304 for (TypeKind actual : actuals) {
305 if (!actual.isSubtypeOf(formals.head))
306 return false; //type mismatch
307 formals = formals.tail.isEmpty() ?
308 formals :
309 formals.tail;
310 }
311 return true;
312 }
313
314 boolean isMoreSpecificThan(VarargsMethod that) {
315 List<TypeKind> actuals = parameterTypes.typeKindList;
316 List<TypeKind> formals = that.parameterTypes.typeKindList;
317 int checks = 0;
318 int expectedCheck = Math.max(actuals.size(), formals.size());
319 while (checks < expectedCheck) {
320 if (!actuals.head.isSubtypeOf(formals.head))
321 return false; //type mismatch
322 formals = formals.tail.isEmpty() ?
323 formals :
324 formals.tail;
325 actuals = actuals.tail.isEmpty() ?
326 actuals :
327 actuals.tail;
328 checks++;
329 }
330 return true;
331 }
332 }
333
334 static class ErrorChecker
335 implements javax.tools.DiagnosticListener<JavaFileObject> {
336
337 boolean errorFound;
338 List<String> errDiags = List.nil();
339
340 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
341 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
342 errDiags = errDiags
343 .append(diagnostic.getMessage(Locale.getDefault()));
344 errorFound = true;
345 }
346 }
347
348 String printDiags() {
349 StringBuilder buf = new StringBuilder();
350 for (String s : errDiags) {
351 buf.append(s);
352 buf.append("\n");
353 }
354 return buf.toString();
355 }
356 }
357
358 //number of bytecode checks made while running combo tests
359 static AtomicInteger bytecodeCheckCount = new AtomicInteger();
360
361 }

mercurial