test/tools/javac/varargs/6199075/T6199075.java

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 */
aoqi@0 23
aoqi@0 24 /*
aoqi@0 25 * @test
aoqi@0 26 * @bug 6199075
aoqi@0 27 *
aoqi@0 28 * @summary Unambiguous varargs method calls flagged as ambiguous
aoqi@0 29 * @author mcimadamore
aoqi@0 30 *
aoqi@0 31 */
aoqi@0 32
aoqi@0 33 import com.sun.source.util.JavacTask;
aoqi@0 34 import com.sun.tools.classfile.Instruction;
aoqi@0 35 import com.sun.tools.classfile.Attribute;
aoqi@0 36 import com.sun.tools.classfile.ClassFile;
aoqi@0 37 import com.sun.tools.classfile.Code_attribute;
aoqi@0 38 import com.sun.tools.classfile.ConstantPool.*;
aoqi@0 39 import com.sun.tools.classfile.Method;
aoqi@0 40 import com.sun.tools.javac.api.JavacTool;
aoqi@0 41 import com.sun.tools.javac.util.List;
aoqi@0 42
aoqi@0 43 import java.io.File;
aoqi@0 44 import java.net.URI;
aoqi@0 45 import java.util.Arrays;
aoqi@0 46 import java.util.Locale;
aoqi@0 47 import javax.tools.Diagnostic;
aoqi@0 48 import javax.tools.JavaCompiler;
aoqi@0 49 import javax.tools.JavaFileObject;
aoqi@0 50 import javax.tools.SimpleJavaFileObject;
aoqi@0 51 import javax.tools.StandardJavaFileManager;
aoqi@0 52 import javax.tools.ToolProvider;
aoqi@0 53
aoqi@0 54 public class T6199075 {
aoqi@0 55
aoqi@0 56 int checkCount = 0;
aoqi@0 57 int bytecodeCheckCount = 0;
aoqi@0 58
aoqi@0 59 enum TypeKind {
aoqi@0 60 BYTE("byte", "(byte)1", "[B", 0),
aoqi@0 61 CHAR("char", "'c'", "[C", 1),
aoqi@0 62 SHORT("short", "(short)1", "[S", 2),
aoqi@0 63 INT("int", "1", "[I", 3),
aoqi@0 64 LONG("long", "1L", "[J", 4),
aoqi@0 65 FLOAT("float", "1.0F", "[F", 5),
aoqi@0 66 DOUBLE("double", "1.0D", "[D", 6),
aoqi@0 67 BOOLEAN("boolean", "true", "[Z", -1);
aoqi@0 68
aoqi@0 69 String typeString;
aoqi@0 70 String valueString;
aoqi@0 71 String bytecodeString;
aoqi@0 72 private int subtypeTag;
aoqi@0 73
aoqi@0 74 TypeKind(String typeString, String valueString, String bytecodeString, int subtypeTag) {
aoqi@0 75 this.typeString = typeString;
aoqi@0 76 this.valueString = valueString;
aoqi@0 77 this.bytecodeString = bytecodeString;
aoqi@0 78 this.subtypeTag = subtypeTag;
aoqi@0 79 }
aoqi@0 80
aoqi@0 81 boolean isSubtypeOf(TypeKind that) {
aoqi@0 82 switch (this) {
aoqi@0 83 case BOOLEAN:
aoqi@0 84 return that == BOOLEAN;
aoqi@0 85 case BYTE:
aoqi@0 86 case CHAR:
aoqi@0 87 return this.subtypeTag == that.subtypeTag ||
aoqi@0 88 this.subtypeTag + 2 <= that.subtypeTag;
aoqi@0 89 default:
aoqi@0 90 return this.subtypeTag <= that.subtypeTag;
aoqi@0 91 }
aoqi@0 92 }
aoqi@0 93 }
aoqi@0 94
aoqi@0 95 enum ArgumentsArity {
aoqi@0 96 ZERO(0),
aoqi@0 97 ONE(1),
aoqi@0 98 TWO(2),
aoqi@0 99 THREE(3);
aoqi@0 100
aoqi@0 101 int arity;
aoqi@0 102
aoqi@0 103 ArgumentsArity(int arity) {
aoqi@0 104 this.arity = arity;
aoqi@0 105 }
aoqi@0 106
aoqi@0 107 String asExpressionList(TypeKind type) {
aoqi@0 108 StringBuilder buf = new StringBuilder();
aoqi@0 109 String sep = "";
aoqi@0 110 for (int i = 0; i < arity; i++) {
aoqi@0 111 buf.append(sep);
aoqi@0 112 buf.append(type.valueString);
aoqi@0 113 sep = ",";
aoqi@0 114 }
aoqi@0 115 return buf.toString();
aoqi@0 116 }
aoqi@0 117 }
aoqi@0 118
aoqi@0 119 static class VarargsMethod {
aoqi@0 120 TypeKind varargsElement;
aoqi@0 121
aoqi@0 122 VarargsMethod(TypeKind varargsElement) {
aoqi@0 123 this.varargsElement = varargsElement;
aoqi@0 124 }
aoqi@0 125
aoqi@0 126 @Override
aoqi@0 127 public String toString() {
aoqi@0 128 return "void m("+ varargsElement.typeString+ "... args) {}";
aoqi@0 129 }
aoqi@0 130
aoqi@0 131 boolean isApplicable(TypeKind actual, ArgumentsArity argsArity) {
aoqi@0 132 return argsArity == ArgumentsArity.ZERO ||
aoqi@0 133 actual.isSubtypeOf(varargsElement);
aoqi@0 134 }
aoqi@0 135
aoqi@0 136 boolean isMoreSpecificThan(VarargsMethod that) {
aoqi@0 137 return varargsElement.isSubtypeOf(that.varargsElement);
aoqi@0 138 }
aoqi@0 139 }
aoqi@0 140
aoqi@0 141 public static void main(String... args) throws Exception {
aoqi@0 142 new T6199075().test();
aoqi@0 143 }
aoqi@0 144
aoqi@0 145 void test() throws Exception {
aoqi@0 146 for (TypeKind formal1 : TypeKind.values()) {
aoqi@0 147 VarargsMethod m1 = new VarargsMethod(formal1);
aoqi@0 148 for (TypeKind formal2 : TypeKind.values()) {
aoqi@0 149 VarargsMethod m2 = new VarargsMethod(formal2);
aoqi@0 150 for (TypeKind actual : TypeKind.values()) {
aoqi@0 151 for (ArgumentsArity argsArity : ArgumentsArity.values()) {
aoqi@0 152 compileAndCheck(m1, m2, actual, argsArity);
aoqi@0 153 }
aoqi@0 154 }
aoqi@0 155 }
aoqi@0 156 }
aoqi@0 157
aoqi@0 158 System.out.println("Total checks made: " + checkCount);
aoqi@0 159 System.out.println("Bytecode checks made: " + bytecodeCheckCount);
aoqi@0 160 }
aoqi@0 161
aoqi@0 162 // Create a single file manager and reuse it for each compile to save time.
aoqi@0 163 StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
aoqi@0 164
aoqi@0 165 void compileAndCheck(VarargsMethod m1, VarargsMethod m2, TypeKind actual, ArgumentsArity argsArity) throws Exception {
aoqi@0 166 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
aoqi@0 167 JavaSource source = new JavaSource(m1, m2, actual, argsArity);
aoqi@0 168 ErrorChecker ec = new ErrorChecker();
aoqi@0 169 JavacTask ct = (JavacTask)tool.getTask(null, fm, ec,
aoqi@0 170 null, null, Arrays.asList(source));
aoqi@0 171 ct.generate();
aoqi@0 172 check(source, ec, m1, m2, actual, argsArity);
aoqi@0 173 }
aoqi@0 174
aoqi@0 175 void check(JavaSource source, ErrorChecker ec, VarargsMethod m1, VarargsMethod m2, TypeKind actual, ArgumentsArity argsArity) {
aoqi@0 176 checkCount++;
aoqi@0 177 boolean resolutionError = false;
aoqi@0 178 VarargsMethod selectedMethod = null;
aoqi@0 179
aoqi@0 180 boolean m1_applicable = m1.isApplicable(actual, argsArity);
aoqi@0 181 boolean m2_applicable = m2.isApplicable(actual, argsArity);
aoqi@0 182
aoqi@0 183 if (!m1_applicable && !m2_applicable) {
aoqi@0 184 resolutionError = true;
aoqi@0 185 } else if (m1_applicable && m2_applicable) {
aoqi@0 186 //most specific
aoqi@0 187 boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
aoqi@0 188 boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
aoqi@0 189 resolutionError = m1_moreSpecific == m2_moreSpecific;
aoqi@0 190 selectedMethod = m1_moreSpecific ? m1 : m2;
aoqi@0 191 } else {
aoqi@0 192 selectedMethod = m1_applicable ?
aoqi@0 193 m1 : m2;
aoqi@0 194 }
aoqi@0 195
aoqi@0 196 if (ec.errorFound != resolutionError) {
aoqi@0 197 throw new Error("invalid diagnostics for source:\n" +
aoqi@0 198 source.getCharContent(true) +
aoqi@0 199 "\nExpected resolution error: " + resolutionError +
aoqi@0 200 "\nFound error: " + ec.errorFound +
aoqi@0 201 "\nCompiler diagnostics:\n" + ec.printDiags());
aoqi@0 202 } else if (!resolutionError) {
aoqi@0 203 verifyBytecode(selectedMethod);
aoqi@0 204 }
aoqi@0 205 }
aoqi@0 206
aoqi@0 207 void verifyBytecode(VarargsMethod selected) {
aoqi@0 208 bytecodeCheckCount++;
aoqi@0 209 File compiledTest = new File("Test.class");
aoqi@0 210 try {
aoqi@0 211 ClassFile cf = ClassFile.read(compiledTest);
aoqi@0 212 Method testMethod = null;
aoqi@0 213 for (Method m : cf.methods) {
aoqi@0 214 if (m.getName(cf.constant_pool).equals("test")) {
aoqi@0 215 testMethod = m;
aoqi@0 216 break;
aoqi@0 217 }
aoqi@0 218 }
aoqi@0 219 if (testMethod == null) {
aoqi@0 220 throw new Error("Test method not found");
aoqi@0 221 }
aoqi@0 222 Code_attribute ea = (Code_attribute)testMethod.attributes.get(Attribute.Code);
aoqi@0 223 if (testMethod == null) {
aoqi@0 224 throw new Error("Code attribute for test() method not found");
aoqi@0 225 }
aoqi@0 226
aoqi@0 227 for (Instruction i : ea.getInstructions()) {
aoqi@0 228 if (i.getMnemonic().equals("invokevirtual")) {
aoqi@0 229 int cp_entry = i.getUnsignedShort(1);
aoqi@0 230 CONSTANT_Methodref_info methRef =
aoqi@0 231 (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
aoqi@0 232 String type = methRef.getNameAndTypeInfo().getType();
aoqi@0 233 if (!type.contains(selected.varargsElement.bytecodeString)) {
aoqi@0 234 throw new Error("Unexpected type method call: " + type);
aoqi@0 235 }
aoqi@0 236 break;
aoqi@0 237 }
aoqi@0 238 }
aoqi@0 239 } catch (Exception e) {
aoqi@0 240 e.printStackTrace();
aoqi@0 241 throw new Error("error reading " + compiledTest +": " + e);
aoqi@0 242 }
aoqi@0 243 }
aoqi@0 244
aoqi@0 245 static class JavaSource extends SimpleJavaFileObject {
aoqi@0 246
aoqi@0 247 static final String source_template = "class Test {\n" +
aoqi@0 248 " #V1\n" +
aoqi@0 249 " #V2\n" +
aoqi@0 250 " void test() { m(#E); }\n" +
aoqi@0 251 "}";
aoqi@0 252
aoqi@0 253 String source;
aoqi@0 254
aoqi@0 255 public JavaSource(VarargsMethod m1, VarargsMethod m2, TypeKind actual, ArgumentsArity argsArity) {
aoqi@0 256 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
aoqi@0 257 source = source_template.replaceAll("#V1", m1.toString()).
aoqi@0 258 replaceAll("#V2", m2.toString()).
aoqi@0 259 replaceAll("#E", argsArity.asExpressionList(actual));
aoqi@0 260 }
aoqi@0 261
aoqi@0 262 @Override
aoqi@0 263 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
aoqi@0 264 return source;
aoqi@0 265 }
aoqi@0 266 }
aoqi@0 267
aoqi@0 268 static class ErrorChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
aoqi@0 269
aoqi@0 270 boolean errorFound;
aoqi@0 271 List<String> errDiags = List.nil();
aoqi@0 272
aoqi@0 273 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
aoqi@0 274 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
aoqi@0 275 errDiags = errDiags.append(diagnostic.getMessage(Locale.getDefault()));
aoqi@0 276 errorFound = true;
aoqi@0 277 }
aoqi@0 278 }
aoqi@0 279
aoqi@0 280 String printDiags() {
aoqi@0 281 StringBuilder buf = new StringBuilder();
aoqi@0 282 for (String s : errDiags) {
aoqi@0 283 buf.append(s);
aoqi@0 284 buf.append("\n");
aoqi@0 285 }
aoqi@0 286 return buf.toString();
aoqi@0 287 }
aoqi@0 288 }
aoqi@0 289 }

mercurial