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

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 1520
5c956be64b9e
parent 0
959103a6100f
permissions
-rw-r--r--

merge

     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  */
    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  */
    34 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
    35 // see JDK-8006746
    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;
    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;
    57 public class T7042566
    58     extends JavacTestingAbstractThreadedTest
    59     implements Runnable {
    61     VarargsMethod m1;
    62     VarargsMethod m2;
    63     TypeConfiguration actuals;
    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     }
    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     }
    84     void check(JavaSource source, ErrorChecker ec, int id) {
    85         boolean resolutionError = false;
    86         VarargsMethod selectedMethod = null;
    88         boolean m1_applicable = m1.isApplicable(actuals);
    89         boolean m2_applicable = m2.isApplicable(actuals);
    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);
    98             resolutionError = m1_moreSpecific == m2_moreSpecific;
    99             selectedMethod = m1_moreSpecific ? m1 : m2;
   100         } else {
   101             selectedMethod = m1_applicable ?
   102                 m1 : m2;
   103         }
   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     }
   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             }
   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     }
   159     class JavaSource extends SimpleJavaFileObject {
   161         static final String source_template = "class Test#ID {\n" +
   162                 "   #V1\n" +
   163                 "   #V2\n" +
   164                 "   void test() { m(#E); }\n" +
   165                 "}";
   167         String source;
   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         }
   178         @Override
   179         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   180             return source;
   181         }
   182     }
   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         }
   193         outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get());
   194         checkAfterExec();
   195     }
   197     enum TypeKind {
   198         OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
   199         STRING("String", "(String)null", "Ljava/lang/String;");
   201         String typeString;
   202         String valueString;
   203         String bytecodeString;
   205         TypeKind(String typeString, String valueString, String bytecodeString) {
   206             this.typeString = typeString;
   207             this.valueString = valueString;
   208             this.bytecodeString = bytecodeString;
   209         }
   211         boolean isSubtypeOf(TypeKind that) {
   212             return that == OBJECT ||
   213                     (that == STRING && this == STRING);
   214         }
   215     }
   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);
   233         List<TypeKind> typeKindList;
   234         String expressionListStr;
   235         String parameterListStr;
   236         String bytecodeSigStr;
   238         private TypeConfiguration(TypeKind... typeKindList) {
   239             this.typeKindList = List.from(typeKindList);
   240             expressionListStr = asExpressionList();
   241             parameterListStr = asParameterList();
   242             bytecodeSigStr = asBytecodeString();
   243         }
   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         }
   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         }
   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     }
   287     static class VarargsMethod {
   288         TypeConfiguration parameterTypes;
   290         public VarargsMethod(TypeConfiguration parameterTypes) {
   291             this.parameterTypes = parameterTypes;
   292         }
   294         @Override
   295         public String toString() {
   296             return "void m( " + parameterTypes.parameterListStr + ") {}";
   297         }
   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         }
   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     }
   334     static class ErrorChecker
   335         implements javax.tools.DiagnosticListener<JavaFileObject> {
   337         boolean errorFound;
   338         List<String> errDiags = List.nil();
   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         }
   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     }
   358     //number of bytecode checks made while running combo tests
   359     static AtomicInteger bytecodeCheckCount = new AtomicInteger();
   361 }

mercurial