23 |
23 |
24 /* |
24 /* |
25 * @test |
25 * @test |
26 * @bug 7042566 |
26 * @bug 7042566 |
27 * @summary Unambiguous varargs method calls flagged as ambiguous |
27 * @summary Unambiguous varargs method calls flagged as ambiguous |
|
28 * @library ../../lib |
|
29 * @build JavacTestingAbstractThreadedTest |
|
30 * @run main T7042566 |
28 */ |
31 */ |
|
32 |
|
33 import java.io.File; |
|
34 import java.net.URI; |
|
35 import java.util.Arrays; |
|
36 import java.util.Locale; |
|
37 import java.util.concurrent.atomic.AtomicInteger; |
|
38 import javax.tools.Diagnostic; |
|
39 import javax.tools.JavaCompiler; |
|
40 import javax.tools.JavaFileObject; |
|
41 import javax.tools.SimpleJavaFileObject; |
|
42 import javax.tools.ToolProvider; |
29 |
43 |
30 import com.sun.source.util.JavacTask; |
44 import com.sun.source.util.JavacTask; |
31 import com.sun.tools.classfile.Instruction; |
45 import com.sun.tools.classfile.Instruction; |
32 import com.sun.tools.classfile.Attribute; |
46 import com.sun.tools.classfile.Attribute; |
33 import com.sun.tools.classfile.ClassFile; |
47 import com.sun.tools.classfile.ClassFile; |
34 import com.sun.tools.classfile.Code_attribute; |
48 import com.sun.tools.classfile.Code_attribute; |
35 import com.sun.tools.classfile.ConstantPool.*; |
49 import com.sun.tools.classfile.ConstantPool.*; |
36 import com.sun.tools.classfile.Method; |
50 import com.sun.tools.classfile.Method; |
37 import com.sun.tools.javac.api.JavacTool; |
|
38 import com.sun.tools.javac.util.List; |
51 import com.sun.tools.javac.util.List; |
39 |
52 |
40 import java.io.File; |
53 public class T7042566 |
41 import java.net.URI; |
54 extends JavacTestingAbstractThreadedTest |
42 import java.util.Arrays; |
55 implements Runnable { |
43 import java.util.Locale; |
|
44 import javax.tools.Diagnostic; |
|
45 import javax.tools.JavaCompiler; |
|
46 import javax.tools.JavaFileObject; |
|
47 import javax.tools.SimpleJavaFileObject; |
|
48 import javax.tools.StandardJavaFileManager; |
|
49 import javax.tools.ToolProvider; |
|
50 |
|
51 public class T7042566 { |
|
52 |
56 |
53 VarargsMethod m1; |
57 VarargsMethod m1; |
54 VarargsMethod m2; |
58 VarargsMethod m2; |
55 TypeConfiguration actuals; |
59 TypeConfiguration actuals; |
56 |
60 |
57 T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf, TypeConfiguration actuals) { |
61 T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf, |
|
62 TypeConfiguration actuals) { |
58 this.m1 = new VarargsMethod(m1_conf); |
63 this.m1 = new VarargsMethod(m1_conf); |
59 this.m2 = new VarargsMethod(m2_conf); |
64 this.m2 = new VarargsMethod(m2_conf); |
60 this.actuals = actuals; |
65 this.actuals = actuals; |
61 } |
66 } |
62 |
67 |
63 void compileAndCheck() throws Exception { |
68 @Override |
|
69 public void run() { |
|
70 int id = checkCount.incrementAndGet(); |
64 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
71 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
65 JavaSource source = new JavaSource(); |
72 JavaSource source = new JavaSource(id); |
66 ErrorChecker ec = new ErrorChecker(); |
73 ErrorChecker ec = new ErrorChecker(); |
67 JavacTask ct = (JavacTask)tool.getTask(null, fm, ec, |
74 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), ec, |
68 null, null, Arrays.asList(source)); |
75 null, null, Arrays.asList(source)); |
69 ct.call(); |
76 ct.call(); |
70 check(source, ec); |
77 check(source, ec, id); |
71 } |
78 } |
72 |
79 |
73 void check(JavaSource source, ErrorChecker ec) { |
80 void check(JavaSource source, ErrorChecker ec, int id) { |
74 checkCount++; |
|
75 boolean resolutionError = false; |
81 boolean resolutionError = false; |
76 VarargsMethod selectedMethod = null; |
82 VarargsMethod selectedMethod = null; |
77 |
83 |
78 boolean m1_applicable = m1.isApplicable(actuals); |
84 boolean m1_applicable = m1.isApplicable(actuals); |
79 boolean m2_applicable = m2.isApplicable(actuals); |
85 boolean m2_applicable = m2.isApplicable(actuals); |
97 source.getCharContent(true) + |
103 source.getCharContent(true) + |
98 "\nExpected resolution error: " + resolutionError + |
104 "\nExpected resolution error: " + resolutionError + |
99 "\nFound error: " + ec.errorFound + |
105 "\nFound error: " + ec.errorFound + |
100 "\nCompiler diagnostics:\n" + ec.printDiags()); |
106 "\nCompiler diagnostics:\n" + ec.printDiags()); |
101 } else if (!resolutionError) { |
107 } else if (!resolutionError) { |
102 verifyBytecode(selectedMethod, source); |
108 verifyBytecode(selectedMethod, source, id); |
103 } |
109 } |
104 } |
110 } |
105 |
111 |
106 void verifyBytecode(VarargsMethod selected, JavaSource source) { |
112 void verifyBytecode(VarargsMethod selected, JavaSource source, int id) { |
107 bytecodeCheckCount++; |
113 bytecodeCheckCount.incrementAndGet(); |
108 File compiledTest = new File("Test.class"); |
114 File compiledTest = new File(String.format("Test%d.class", id)); |
109 try { |
115 try { |
110 ClassFile cf = ClassFile.read(compiledTest); |
116 ClassFile cf = ClassFile.read(compiledTest); |
111 Method testMethod = null; |
117 Method testMethod = null; |
112 for (Method m : cf.methods) { |
118 for (Method m : cf.methods) { |
113 if (m.getName(cf.constant_pool).equals("test")) { |
119 if (m.getName(cf.constant_pool).equals("test")) { |
116 } |
122 } |
117 } |
123 } |
118 if (testMethod == null) { |
124 if (testMethod == null) { |
119 throw new Error("Test method not found"); |
125 throw new Error("Test method not found"); |
120 } |
126 } |
121 Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code); |
127 Code_attribute ea = |
|
128 (Code_attribute)testMethod.attributes.get(Attribute.Code); |
122 if (testMethod == null) { |
129 if (testMethod == null) { |
123 throw new Error("Code attribute for test() method not found"); |
130 throw new Error("Code attribute for test() method not found"); |
124 } |
131 } |
125 |
132 |
126 for (Instruction i : ea.getInstructions()) { |
133 for (Instruction i : ea.getInstructions()) { |
127 if (i.getMnemonic().equals("invokevirtual")) { |
134 if (i.getMnemonic().equals("invokevirtual")) { |
128 int cp_entry = i.getUnsignedShort(1); |
135 int cp_entry = i.getUnsignedShort(1); |
129 CONSTANT_Methodref_info methRef = |
136 CONSTANT_Methodref_info methRef = |
130 (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry); |
137 (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry); |
131 String type = methRef.getNameAndTypeInfo().getType(); |
138 String type = methRef.getNameAndTypeInfo().getType(); |
132 String sig = selected.parameterTypes.bytecodeSigStr; |
139 String sig = selected.parameterTypes.bytecodeSigStr; |
133 if (!type.contains(sig)) { |
140 if (!type.contains(sig)) { |
134 throw new Error("Unexpected type method call: " + type + "" + |
141 throw new Error("Unexpected type method call: " + |
|
142 type + "" + |
135 "\nfound: " + sig + |
143 "\nfound: " + sig + |
136 "\n" + source.getCharContent(true)); |
144 "\n" + source.getCharContent(true)); |
137 } |
145 } |
138 break; |
146 break; |
139 } |
147 } |
144 } |
152 } |
145 } |
153 } |
146 |
154 |
147 class JavaSource extends SimpleJavaFileObject { |
155 class JavaSource extends SimpleJavaFileObject { |
148 |
156 |
149 static final String source_template = "class Test {\n" + |
157 static final String source_template = "class Test#ID {\n" + |
150 " #V1\n" + |
158 " #V1\n" + |
151 " #V2\n" + |
159 " #V2\n" + |
152 " void test() { m(#E); }\n" + |
160 " void test() { m(#E); }\n" + |
153 "}"; |
161 "}"; |
154 |
162 |
155 String source; |
163 String source; |
156 |
164 |
157 public JavaSource() { |
165 public JavaSource(int id) { |
158 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); |
166 super(URI.create(String.format("myfo:/Test%d.java", id)), |
159 source = source_template.replaceAll("#V1", m1.toString()). |
167 JavaFileObject.Kind.SOURCE); |
160 replaceAll("#V2", m2.toString()). |
168 source = source_template.replaceAll("#V1", m1.toString()) |
161 replaceAll("#E", actuals.expressionListStr); |
169 .replaceAll("#V2", m2.toString()) |
|
170 .replaceAll("#E", actuals.expressionListStr) |
|
171 .replaceAll("#ID", String.valueOf(id)); |
162 } |
172 } |
163 |
173 |
164 @Override |
174 @Override |
165 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
175 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
166 return source; |
176 return source; |
167 } |
177 } |
168 } |
178 } |
169 |
|
170 /** global decls ***/ |
|
171 |
|
172 // Create a single file manager and reuse it for each compile to save time. |
|
173 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); |
|
174 |
|
175 //statistics |
|
176 static int checkCount = 0; |
|
177 static int bytecodeCheckCount = 0; |
|
178 |
179 |
179 public static void main(String... args) throws Exception { |
180 public static void main(String... args) throws Exception { |
180 for (TypeConfiguration tconf1 : TypeConfiguration.values()) { |
181 for (TypeConfiguration tconf1 : TypeConfiguration.values()) { |
181 for (TypeConfiguration tconf2 : TypeConfiguration.values()) { |
182 for (TypeConfiguration tconf2 : TypeConfiguration.values()) { |
182 for (TypeConfiguration tconf3 : TypeConfiguration.values()) { |
183 for (TypeConfiguration tconf3 : TypeConfiguration.values()) { |
183 new T7042566(tconf1, tconf2, tconf3).compileAndCheck(); |
184 pool.execute(new T7042566(tconf1, tconf2, tconf3)); |
184 } |
185 } |
185 } |
186 } |
186 } |
187 } |
187 |
188 |
188 System.out.println("Total checks made: " + checkCount); |
189 outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get()); |
189 System.out.println("Bytecode checks made: " + bytecodeCheckCount); |
190 checkAfterExec(); |
190 } |
191 } |
191 |
192 |
192 enum TypeKind { |
193 enum TypeKind { |
193 OBJECT("Object", "(Object)null", "Ljava/lang/Object;"), |
194 OBJECT("Object", "(Object)null", "Ljava/lang/Object;"), |
194 STRING("String", "(String)null", "Ljava/lang/String;"); |
195 STRING("String", "(String)null", "Ljava/lang/String;"); |