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

Thu, 25 Aug 2011 17:18:25 -0700

author
schien
date
Thu, 25 Aug 2011 17:18:25 -0700
changeset 1067
f497fac86cf9
parent 1006
a2d422d480cb
child 1482
954541f13717
permissions
-rw-r--r--

Added tag jdk8-b02 for changeset b3c059de2a61

mcimadamore@1006 1 /*
mcimadamore@1006 2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
mcimadamore@1006 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@1006 4 *
mcimadamore@1006 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@1006 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@1006 7 * published by the Free Software Foundation.
mcimadamore@1006 8 *
mcimadamore@1006 9 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@1006 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@1006 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@1006 12 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@1006 13 * accompanied this code).
mcimadamore@1006 14 *
mcimadamore@1006 15 * You should have received a copy of the GNU General Public License version
mcimadamore@1006 16 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@1006 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@1006 18 *
mcimadamore@1006 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@1006 20 * or visit www.oracle.com if you need additional information or have any
mcimadamore@1006 21 * questions.
mcimadamore@1006 22 */
mcimadamore@1006 23
mcimadamore@1006 24 /*
mcimadamore@1006 25 * @test
mcimadamore@1006 26 * @bug 7042566
mcimadamore@1006 27 * @summary Unambiguous varargs method calls flagged as ambiguous
mcimadamore@1006 28 */
mcimadamore@1006 29
mcimadamore@1006 30 import com.sun.source.util.JavacTask;
mcimadamore@1006 31 import com.sun.tools.classfile.Instruction;
mcimadamore@1006 32 import com.sun.tools.classfile.Attribute;
mcimadamore@1006 33 import com.sun.tools.classfile.ClassFile;
mcimadamore@1006 34 import com.sun.tools.classfile.Code_attribute;
mcimadamore@1006 35 import com.sun.tools.classfile.ConstantPool.*;
mcimadamore@1006 36 import com.sun.tools.classfile.Method;
mcimadamore@1006 37 import com.sun.tools.javac.api.JavacTool;
mcimadamore@1006 38 import com.sun.tools.javac.util.List;
mcimadamore@1006 39
mcimadamore@1006 40 import java.io.File;
mcimadamore@1006 41 import java.net.URI;
mcimadamore@1006 42 import java.util.Arrays;
mcimadamore@1006 43 import java.util.Locale;
mcimadamore@1006 44 import javax.tools.Diagnostic;
mcimadamore@1006 45 import javax.tools.JavaCompiler;
mcimadamore@1006 46 import javax.tools.JavaFileObject;
mcimadamore@1006 47 import javax.tools.SimpleJavaFileObject;
mcimadamore@1006 48 import javax.tools.StandardJavaFileManager;
mcimadamore@1006 49 import javax.tools.ToolProvider;
mcimadamore@1006 50
mcimadamore@1006 51 public class T7042566 {
mcimadamore@1006 52
mcimadamore@1006 53 VarargsMethod m1;
mcimadamore@1006 54 VarargsMethod m2;
mcimadamore@1006 55 TypeConfiguration actuals;
mcimadamore@1006 56
mcimadamore@1006 57 T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf, TypeConfiguration actuals) {
mcimadamore@1006 58 this.m1 = new VarargsMethod(m1_conf);
mcimadamore@1006 59 this.m2 = new VarargsMethod(m2_conf);
mcimadamore@1006 60 this.actuals = actuals;
mcimadamore@1006 61 }
mcimadamore@1006 62
mcimadamore@1006 63 void compileAndCheck() throws Exception {
mcimadamore@1006 64 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
mcimadamore@1006 65 JavaSource source = new JavaSource();
mcimadamore@1006 66 ErrorChecker ec = new ErrorChecker();
mcimadamore@1006 67 JavacTask ct = (JavacTask)tool.getTask(null, fm, ec,
mcimadamore@1006 68 null, null, Arrays.asList(source));
mcimadamore@1006 69 ct.call();
mcimadamore@1006 70 check(source, ec);
mcimadamore@1006 71 }
mcimadamore@1006 72
mcimadamore@1006 73 void check(JavaSource source, ErrorChecker ec) {
mcimadamore@1006 74 checkCount++;
mcimadamore@1006 75 boolean resolutionError = false;
mcimadamore@1006 76 VarargsMethod selectedMethod = null;
mcimadamore@1006 77
mcimadamore@1006 78 boolean m1_applicable = m1.isApplicable(actuals);
mcimadamore@1006 79 boolean m2_applicable = m2.isApplicable(actuals);
mcimadamore@1006 80
mcimadamore@1006 81 if (!m1_applicable && !m2_applicable) {
mcimadamore@1006 82 resolutionError = true;
mcimadamore@1006 83 } else if (m1_applicable && m2_applicable) {
mcimadamore@1006 84 //most specific
mcimadamore@1006 85 boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
mcimadamore@1006 86 boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
mcimadamore@1006 87
mcimadamore@1006 88 resolutionError = m1_moreSpecific == m2_moreSpecific;
mcimadamore@1006 89 selectedMethod = m1_moreSpecific ? m1 : m2;
mcimadamore@1006 90 } else {
mcimadamore@1006 91 selectedMethod = m1_applicable ?
mcimadamore@1006 92 m1 : m2;
mcimadamore@1006 93 }
mcimadamore@1006 94
mcimadamore@1006 95 if (ec.errorFound != resolutionError) {
mcimadamore@1006 96 throw new Error("invalid diagnostics for source:\n" +
mcimadamore@1006 97 source.getCharContent(true) +
mcimadamore@1006 98 "\nExpected resolution error: " + resolutionError +
mcimadamore@1006 99 "\nFound error: " + ec.errorFound +
mcimadamore@1006 100 "\nCompiler diagnostics:\n" + ec.printDiags());
mcimadamore@1006 101 } else if (!resolutionError) {
mcimadamore@1006 102 verifyBytecode(selectedMethod, source);
mcimadamore@1006 103 }
mcimadamore@1006 104 }
mcimadamore@1006 105
mcimadamore@1006 106 void verifyBytecode(VarargsMethod selected, JavaSource source) {
mcimadamore@1006 107 bytecodeCheckCount++;
mcimadamore@1006 108 File compiledTest = new File("Test.class");
mcimadamore@1006 109 try {
mcimadamore@1006 110 ClassFile cf = ClassFile.read(compiledTest);
mcimadamore@1006 111 Method testMethod = null;
mcimadamore@1006 112 for (Method m : cf.methods) {
mcimadamore@1006 113 if (m.getName(cf.constant_pool).equals("test")) {
mcimadamore@1006 114 testMethod = m;
mcimadamore@1006 115 break;
mcimadamore@1006 116 }
mcimadamore@1006 117 }
mcimadamore@1006 118 if (testMethod == null) {
mcimadamore@1006 119 throw new Error("Test method not found");
mcimadamore@1006 120 }
mcimadamore@1006 121 Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code);
mcimadamore@1006 122 if (testMethod == null) {
mcimadamore@1006 123 throw new Error("Code attribute for test() method not found");
mcimadamore@1006 124 }
mcimadamore@1006 125
mcimadamore@1006 126 for (Instruction i : ea.getInstructions()) {
mcimadamore@1006 127 if (i.getMnemonic().equals("invokevirtual")) {
mcimadamore@1006 128 int cp_entry = i.getUnsignedShort(1);
mcimadamore@1006 129 CONSTANT_Methodref_info methRef =
mcimadamore@1006 130 (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
mcimadamore@1006 131 String type = methRef.getNameAndTypeInfo().getType();
mcimadamore@1006 132 String sig = selected.parameterTypes.bytecodeSigStr;
mcimadamore@1006 133 if (!type.contains(sig)) {
mcimadamore@1006 134 throw new Error("Unexpected type method call: " + type + "" +
mcimadamore@1006 135 "\nfound: " + sig +
mcimadamore@1006 136 "\n" + source.getCharContent(true));
mcimadamore@1006 137 }
mcimadamore@1006 138 break;
mcimadamore@1006 139 }
mcimadamore@1006 140 }
mcimadamore@1006 141 } catch (Exception e) {
mcimadamore@1006 142 e.printStackTrace();
mcimadamore@1006 143 throw new Error("error reading " + compiledTest +": " + e);
mcimadamore@1006 144 }
mcimadamore@1006 145 }
mcimadamore@1006 146
mcimadamore@1006 147 class JavaSource extends SimpleJavaFileObject {
mcimadamore@1006 148
mcimadamore@1006 149 static final String source_template = "class Test {\n" +
mcimadamore@1006 150 " #V1\n" +
mcimadamore@1006 151 " #V2\n" +
mcimadamore@1006 152 " void test() { m(#E); }\n" +
mcimadamore@1006 153 "}";
mcimadamore@1006 154
mcimadamore@1006 155 String source;
mcimadamore@1006 156
mcimadamore@1006 157 public JavaSource() {
mcimadamore@1006 158 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
mcimadamore@1006 159 source = source_template.replaceAll("#V1", m1.toString()).
mcimadamore@1006 160 replaceAll("#V2", m2.toString()).
mcimadamore@1006 161 replaceAll("#E", actuals.expressionListStr);
mcimadamore@1006 162 }
mcimadamore@1006 163
mcimadamore@1006 164 @Override
mcimadamore@1006 165 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
mcimadamore@1006 166 return source;
mcimadamore@1006 167 }
mcimadamore@1006 168 }
mcimadamore@1006 169
mcimadamore@1006 170 /** global decls ***/
mcimadamore@1006 171
mcimadamore@1006 172 // Create a single file manager and reuse it for each compile to save time.
mcimadamore@1006 173 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
mcimadamore@1006 174
mcimadamore@1006 175 //statistics
mcimadamore@1006 176 static int checkCount = 0;
mcimadamore@1006 177 static int bytecodeCheckCount = 0;
mcimadamore@1006 178
mcimadamore@1006 179 public static void main(String... args) throws Exception {
mcimadamore@1006 180 for (TypeConfiguration tconf1 : TypeConfiguration.values()) {
mcimadamore@1006 181 for (TypeConfiguration tconf2 : TypeConfiguration.values()) {
mcimadamore@1006 182 for (TypeConfiguration tconf3 : TypeConfiguration.values()) {
mcimadamore@1006 183 new T7042566(tconf1, tconf2, tconf3).compileAndCheck();
mcimadamore@1006 184 }
mcimadamore@1006 185 }
mcimadamore@1006 186 }
mcimadamore@1006 187
mcimadamore@1006 188 System.out.println("Total checks made: " + checkCount);
mcimadamore@1006 189 System.out.println("Bytecode checks made: " + bytecodeCheckCount);
mcimadamore@1006 190 }
mcimadamore@1006 191
mcimadamore@1006 192 enum TypeKind {
mcimadamore@1006 193 OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
mcimadamore@1006 194 STRING("String", "(String)null", "Ljava/lang/String;");
mcimadamore@1006 195
mcimadamore@1006 196 String typeString;
mcimadamore@1006 197 String valueString;
mcimadamore@1006 198 String bytecodeString;
mcimadamore@1006 199
mcimadamore@1006 200 TypeKind(String typeString, String valueString, String bytecodeString) {
mcimadamore@1006 201 this.typeString = typeString;
mcimadamore@1006 202 this.valueString = valueString;
mcimadamore@1006 203 this.bytecodeString = bytecodeString;
mcimadamore@1006 204 }
mcimadamore@1006 205
mcimadamore@1006 206 boolean isSubtypeOf(TypeKind that) {
mcimadamore@1006 207 return that == OBJECT ||
mcimadamore@1006 208 (that == STRING && this == STRING);
mcimadamore@1006 209 }
mcimadamore@1006 210 }
mcimadamore@1006 211
mcimadamore@1006 212 enum TypeConfiguration {
mcimadamore@1006 213 A(TypeKind.OBJECT),
mcimadamore@1006 214 B(TypeKind.STRING),
mcimadamore@1006 215 AA(TypeKind.OBJECT, TypeKind.OBJECT),
mcimadamore@1006 216 AB(TypeKind.OBJECT, TypeKind.STRING),
mcimadamore@1006 217 BA(TypeKind.STRING, TypeKind.OBJECT),
mcimadamore@1006 218 BB(TypeKind.STRING, TypeKind.STRING),
mcimadamore@1006 219 AAA(TypeKind.OBJECT, TypeKind.OBJECT, TypeKind.OBJECT),
mcimadamore@1006 220 AAB(TypeKind.OBJECT, TypeKind.OBJECT, TypeKind.STRING),
mcimadamore@1006 221 ABA(TypeKind.OBJECT, TypeKind.STRING, TypeKind.OBJECT),
mcimadamore@1006 222 ABB(TypeKind.OBJECT, TypeKind.STRING, TypeKind.STRING),
mcimadamore@1006 223 BAA(TypeKind.STRING, TypeKind.OBJECT, TypeKind.OBJECT),
mcimadamore@1006 224 BAB(TypeKind.STRING, TypeKind.OBJECT, TypeKind.STRING),
mcimadamore@1006 225 BBA(TypeKind.STRING, TypeKind.STRING, TypeKind.OBJECT),
mcimadamore@1006 226 BBB(TypeKind.STRING, TypeKind.STRING, TypeKind.STRING);
mcimadamore@1006 227
mcimadamore@1006 228 List<TypeKind> typeKindList;
mcimadamore@1006 229 String expressionListStr;
mcimadamore@1006 230 String parameterListStr;
mcimadamore@1006 231 String bytecodeSigStr;
mcimadamore@1006 232
mcimadamore@1006 233 private TypeConfiguration(TypeKind... typeKindList) {
mcimadamore@1006 234 this.typeKindList = List.from(typeKindList);
mcimadamore@1006 235 expressionListStr = asExpressionList();
mcimadamore@1006 236 parameterListStr = asParameterList();
mcimadamore@1006 237 bytecodeSigStr = asBytecodeString();
mcimadamore@1006 238 }
mcimadamore@1006 239
mcimadamore@1006 240 private String asExpressionList() {
mcimadamore@1006 241 StringBuilder buf = new StringBuilder();
mcimadamore@1006 242 String sep = "";
mcimadamore@1006 243 for (TypeKind tk : typeKindList) {
mcimadamore@1006 244 buf.append(sep);
mcimadamore@1006 245 buf.append(tk.valueString);
mcimadamore@1006 246 sep = ",";
mcimadamore@1006 247 }
mcimadamore@1006 248 return buf.toString();
mcimadamore@1006 249 }
mcimadamore@1006 250
mcimadamore@1006 251 private String asParameterList() {
mcimadamore@1006 252 StringBuilder buf = new StringBuilder();
mcimadamore@1006 253 String sep = "";
mcimadamore@1006 254 int count = 0;
mcimadamore@1006 255 for (TypeKind arg : typeKindList) {
mcimadamore@1006 256 buf.append(sep);
mcimadamore@1006 257 buf.append(arg.typeString);
mcimadamore@1006 258 if (count == (typeKindList.size() - 1)) {
mcimadamore@1006 259 buf.append("...");
mcimadamore@1006 260 }
mcimadamore@1006 261 buf.append(" ");
mcimadamore@1006 262 buf.append("arg" + count++);
mcimadamore@1006 263 sep = ",";
mcimadamore@1006 264 }
mcimadamore@1006 265 return buf.toString();
mcimadamore@1006 266 }
mcimadamore@1006 267
mcimadamore@1006 268 private String asBytecodeString() {
mcimadamore@1006 269 StringBuilder buf = new StringBuilder();
mcimadamore@1006 270 int count = 0;
mcimadamore@1006 271 for (TypeKind arg : typeKindList) {
mcimadamore@1006 272 if (count == (typeKindList.size() - 1)) {
mcimadamore@1006 273 buf.append("[");
mcimadamore@1006 274 }
mcimadamore@1006 275 buf.append(arg.bytecodeString);
mcimadamore@1006 276 count++;
mcimadamore@1006 277 }
mcimadamore@1006 278 return buf.toString();
mcimadamore@1006 279 }
mcimadamore@1006 280 }
mcimadamore@1006 281
mcimadamore@1006 282 static class VarargsMethod {
mcimadamore@1006 283 TypeConfiguration parameterTypes;
mcimadamore@1006 284
mcimadamore@1006 285 public VarargsMethod(TypeConfiguration parameterTypes) {
mcimadamore@1006 286 this.parameterTypes = parameterTypes;
mcimadamore@1006 287 }
mcimadamore@1006 288
mcimadamore@1006 289 @Override
mcimadamore@1006 290 public String toString() {
mcimadamore@1006 291 return "void m( " + parameterTypes.parameterListStr + ") {}";
mcimadamore@1006 292 }
mcimadamore@1006 293
mcimadamore@1006 294 boolean isApplicable(TypeConfiguration that) {
mcimadamore@1006 295 List<TypeKind> actuals = that.typeKindList;
mcimadamore@1006 296 List<TypeKind> formals = parameterTypes.typeKindList;
mcimadamore@1006 297 if ((actuals.size() - formals.size()) < -1)
mcimadamore@1006 298 return false; //not enough args
mcimadamore@1006 299 for (TypeKind actual : actuals) {
mcimadamore@1006 300 if (!actual.isSubtypeOf(formals.head))
mcimadamore@1006 301 return false; //type mismatch
mcimadamore@1006 302 formals = formals.tail.isEmpty() ?
mcimadamore@1006 303 formals :
mcimadamore@1006 304 formals.tail;
mcimadamore@1006 305 }
mcimadamore@1006 306 return true;
mcimadamore@1006 307 }
mcimadamore@1006 308
mcimadamore@1006 309 boolean isMoreSpecificThan(VarargsMethod that) {
mcimadamore@1006 310 List<TypeKind> actuals = parameterTypes.typeKindList;
mcimadamore@1006 311 List<TypeKind> formals = that.parameterTypes.typeKindList;
mcimadamore@1006 312 int checks = 0;
mcimadamore@1006 313 int expectedCheck = Math.max(actuals.size(), formals.size());
mcimadamore@1006 314 while (checks < expectedCheck) {
mcimadamore@1006 315 if (!actuals.head.isSubtypeOf(formals.head))
mcimadamore@1006 316 return false; //type mismatch
mcimadamore@1006 317 formals = formals.tail.isEmpty() ?
mcimadamore@1006 318 formals :
mcimadamore@1006 319 formals.tail;
mcimadamore@1006 320 actuals = actuals.tail.isEmpty() ?
mcimadamore@1006 321 actuals :
mcimadamore@1006 322 actuals.tail;
mcimadamore@1006 323 checks++;
mcimadamore@1006 324 }
mcimadamore@1006 325 return true;
mcimadamore@1006 326 }
mcimadamore@1006 327 }
mcimadamore@1006 328
mcimadamore@1006 329 static class ErrorChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
mcimadamore@1006 330
mcimadamore@1006 331 boolean errorFound;
mcimadamore@1006 332 List<String> errDiags = List.nil();
mcimadamore@1006 333
mcimadamore@1006 334 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
mcimadamore@1006 335 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
mcimadamore@1006 336 errDiags = errDiags.append(diagnostic.getMessage(Locale.getDefault()));
mcimadamore@1006 337 errorFound = true;
mcimadamore@1006 338 }
mcimadamore@1006 339 }
mcimadamore@1006 340
mcimadamore@1006 341 String printDiags() {
mcimadamore@1006 342 StringBuilder buf = new StringBuilder();
mcimadamore@1006 343 for (String s : errDiags) {
mcimadamore@1006 344 buf.append(s);
mcimadamore@1006 345 buf.append("\n");
mcimadamore@1006 346 }
mcimadamore@1006 347 return buf.toString();
mcimadamore@1006 348 }
mcimadamore@1006 349 }
mcimadamore@1006 350 }

mercurial