1 /*
  2  * Copyright (c) 2012, 2018, 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 8003280 8006694 8129962
 27  * @summary Add lambda tests
 28  *  Automatic test for checking correctness of structural most specific test routine
 29  *  temporarily workaround combo tests are causing time out in several platforms
 30  * @library /tools/javac/lib
 31  * @modules jdk.compiler/com.sun.tools.javac.api
 32  *          jdk.compiler/com.sun.tools.javac.file
 33  *          jdk.compiler/com.sun.tools.javac.util
 34  * @build combo.ComboTestHelper
 35 
 36  * @run main StructuralMostSpecificTest
 37  */
 38 
 39 import javax.lang.model.element.Element;
 40 import javax.tools.Diagnostic;
 41 import javax.tools.JavaFileObject;
 42 import com.sun.tools.javac.api.ClientCodeWrapper;
 43 import com.sun.tools.javac.util.JCDiagnostic;
 44 import com.sun.tools.javac.util.List;
 45 import combo.ComboInstance;
 46 import combo.ComboParameter;
 47 import combo.ComboTask.Result;
 48 import combo.ComboTestHelper;
 49 
 50 public class StructuralMostSpecificTest extends ComboInstance<StructuralMostSpecificTest> {
 51 
 52     enum RetTypeKind implements ComboParameter {
 53         SHORT("short"),
 54         INT("int"),
 55         OBJECT("Object"),
 56         INTEGER("Integer"),
 57         VOID("void"),
 58         J_L_VOID("Void");
 59 
 60         String retTypeStr;
 61 
 62         RetTypeKind(String retTypeStr) {
 63             this.retTypeStr = retTypeStr;
 64         }
 65 
 66         boolean moreSpecificThan(RetTypeKind rk) {
 67             return moreSpecificThan[this.ordinal()][rk.ordinal()];
 68         }
 69 
 70         static boolean[][] moreSpecificThan = {
 71                 //              SHORT |  INT  | OBJECT | INTEGER | VOID  | J_L_VOID
 72                 /* SHORT */   { true  , true  , true   , false   , false , false },
 73                 /* INT */     { false , true  , true   , true    , false , false },
 74                 /* OBJECT */  { false , false , true   , false   , false , false },
 75                 /* INTEGER */ { false , false , true   , true    , false , false },
 76                 /* VOID */    { false , false , false  , false   , true  , true  },
 77                 /* J_L_VOID */{ false , false , true   , false   , false , true  } };
 78 
 79         public String expand(String optParameter) {
 80             return retTypeStr;
 81         }
 82     }
 83 
 84     enum ArgTypeKind implements ComboParameter {
 85         SHORT("short"),
 86         INT("int"),
 87         BOOLEAN("boolean"),
 88         OBJECT("Object"),
 89         INTEGER("Integer"),
 90         DOUBLE("Double");
 91 
 92         String argTypeStr;
 93 
 94         ArgTypeKind(String typeStr) {
 95             this.argTypeStr = typeStr;
 96         }
 97 
 98         public String expand(String optParameter) {
 99             return argTypeStr;
100         }
101     }
102 
103     enum ExceptionKind implements ComboParameter {
104         NONE(""),
105         EXCEPTION("throws Exception"),
106         SQL_EXCEPTION("throws java.sql.SQLException"),
107         IO_EXCEPTION("throws java.io.IOException");
108 
109         String exceptionStr;
110 
111         ExceptionKind(String exceptionStr) {
112             this.exceptionStr = exceptionStr;
113         }
114 
115         public String expand(String optParameter) {
116             return exceptionStr;
117         }
118     }
119 
120     enum LambdaReturnKind implements ComboParameter {
121         VOID("return;"),
122         SHORT("return (short)0;"),
123         INT("return 0;"),
124         INTEGER("return (Integer)null;"),
125         NULL("return null;");
126 
127         String retStr;
128 
129         LambdaReturnKind(String retStr) {
130             this.retStr = retStr;
131         }
132 
133         boolean compatibleWith(RetTypeKind rk) {
134             return compatibleWith[rk.ordinal()][ordinal()];
135         }
136 
137         static boolean[][] compatibleWith = {
138                 //              VOID  | SHORT | INT     | INTEGER | NULL
139                 /* SHORT */   { false , true  , false   , false   , false },
140                 /* INT */     { false , true  , true    , true    , false },
141                 /* OBJECT */  { false , true  , true    , true    , true  },
142                 /* INTEGER */ { false , false , true    , true    , true  },
143                 /* VOID */    { true  , false , false   , false   , false },
144                 /* J_L_VOID */{ false , false , false   , false   , true  } };
145 
146         boolean needsConversion(RetTypeKind rk) {
147             return needsConversion[rk.ordinal()][ordinal()];
148         }
149 
150         static boolean[][] needsConversion = {
151                 //              VOID  | SHORT | INT     | INTEGER | NULL
152                 /* SHORT */   { false , false , false   , false   , false },
153                 /* INT */     { false , false , false   , true    , false },
154                 /* OBJECT */  { false , true  , true    , false   , false },
155                 /* INTEGER */ { false , false , true    , false   , false },
156                 /* VOID */    { false , false , false   , false   , false },
157                 /* J_L_VOID */{ true  , false , false   , false   , false } };
158 
159         public String expand(String optParameter) {
160             return retStr;
161         }
162     }
163 
164     static final String sourceTemplate =
165             "interface SAM1 {\n" +
166             "   #{RET[0]} m(#{ARG[0]} a1) #{EX[0]};\n" +
167             "}\n" +
168             "interface SAM2 {\n" +
169             "   #{RET[1]} m(#{ARG[1]} a1) #{EX[1]};\n" +
170             "}\n" +
171             "class Test {\n" +
172             "   void m(SAM1 s) { }\n" +
173             "   void m(SAM2 s) { }\n" +
174             "   { m((#{ARG[0]} x)->{ #{EXPR} }); }\n" +
175             "}\n";
176 
177     public static void main(String... args) throws Exception {
178         new ComboTestHelper<StructuralMostSpecificTest>()
179                 .withFilter(StructuralMostSpecificTest::hasSameArguments)
180                 .withFilter(StructuralMostSpecificTest::hasCompatibleReturns)
181                 .withFilter(StructuralMostSpecificTest::hasSameOverloadPhase)
182                 .withDimension("EXPR", (x, expr) -> x.lambdaReturnKind = expr, LambdaReturnKind.values())
183                 .withArrayDimension("RET", (x, ret, idx) -> x.returnType[idx] = ret, 2, RetTypeKind.values())
184                 .withArrayDimension("EX", 2, ExceptionKind.values())
185                 .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKind[idx] = arg, 2, ArgTypeKind.values())
186                 .run(StructuralMostSpecificTest::new);
187     }
188 
189     LambdaReturnKind lambdaReturnKind;
190     RetTypeKind[] returnType = new RetTypeKind[2];
191     ArgTypeKind[] argumentKind = new ArgTypeKind[2];
192 
193     boolean hasSameArguments() {
194         return argumentKind[0] == argumentKind[1];
195     }
196 
197     boolean hasCompatibleReturns() {
198         return lambdaReturnKind.compatibleWith(returnType[0]) &&
199                 lambdaReturnKind.compatibleWith(returnType[1]);
200     }
201 
202     boolean hasSameOverloadPhase() {
203         return lambdaReturnKind.needsConversion(returnType[0]) == lambdaReturnKind.needsConversion(returnType[1]);
204     }
205 
206     @Override
207     public void doWork() throws Throwable {
208         newCompilationTask()
209                 .withSourceFromTemplate(sourceTemplate)
210                 .withOption("--debug=verboseResolution=all,-predef,-internal,-object-init")
211                 .analyze(this::check);
212     }
213 
214     void check(Result<Iterable<? extends Element>> result) {
215         boolean m1MoreSpecific = returnType[0].moreSpecificThan(returnType[1]);
216         boolean m2MoreSpecific = returnType[1].moreSpecificThan(returnType[0]);
217 
218         boolean ambiguous = (m1MoreSpecific == m2MoreSpecific);
219 
220         if (ambiguous != ambiguityFound(result)) {
221             fail("invalid diagnostics for combo:\n" +
222                 result.compilationInfo() + "\n" +
223                 "\nAmbiguity found: " + ambiguityFound(result) +
224                 "\nm1 more specific: " + m1MoreSpecific +
225                 "\nm2 more specific: " + m2MoreSpecific +
226                 "\nexpected ambiguity: " + ambiguous);
227         }
228 
229         if (!ambiguous) {
230             String sigToCheck = m1MoreSpecific ? "m(SAM1)" : "m(SAM2)";
231             if (!sigToCheck.equals(mostSpecificSignature(result))) {
232                 fail("invalid most specific method selected:\n" +
233                         result.compilationInfo() + "\n" +
234                         "\nMost specific found: " + mostSpecificSignature(result) +
235                         "\nm1 more specific: " + m1MoreSpecific +
236                         "\nm2 more specific: " + m2MoreSpecific);
237             }
238         }
239     }
240 
241     boolean ambiguityFound(Result<Iterable<? extends Element>> result) {
242         return result.containsKey("compiler.err.ref.ambiguous");
243     }
244 
245     String mostSpecificSignature(Result<Iterable<? extends Element>> result) {
246         List<Diagnostic<? extends JavaFileObject>> rsDiag =
247                 result.diagnosticsForKey("compiler.note.verbose.resolve.multi");
248         if (rsDiag.nonEmpty()) {
249             ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
250                         (ClientCodeWrapper.DiagnosticSourceUnwrapper)rsDiag.head;
251             JCDiagnostic.MultilineDiagnostic mdiag =
252                 (JCDiagnostic.MultilineDiagnostic)dsu.d;
253             int mostSpecificIndex = (Integer)mdiag.getArgs()[2];
254             return mdiag.getSubdiagnostics().get(mostSpecificIndex).getArgs()[1].toString();
255         } else {
256             return null;
257         }
258     }
259 }