1 /*
  2  * Copyright (c) 2012, 2015, 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 8004102 8006694 8129962
 27  * @summary Add lambda tests
 28  *  perform several automated checks in lambda conversion, esp. around accessibility
 29  *  temporarily workaround combo tests are causing time out in several platforms
 30  * @enablePreview
 31  * @library /tools/javac/lib
 32  * @modules jdk.compiler/com.sun.tools.javac.api
 33  *          jdk.compiler/com.sun.tools.javac.file
 34  *          jdk.compiler/com.sun.tools.javac.util
 35  * @build combo.ComboTestHelper
 36  * @run main FunctionalInterfaceConversionTest
 37  */
 38 
 39 import java.io.IOException;
 40 
 41 import combo.ComboInstance;
 42 import combo.ComboParameter;
 43 import combo.ComboTask.Result;
 44 import combo.ComboTestHelper;
 45 
 46 
 47 public class FunctionalInterfaceConversionTest extends ComboInstance<FunctionalInterfaceConversionTest> {
 48 
 49     enum PackageKind implements ComboParameter {
 50         NO_PKG(""),
 51         PKG_A("a");
 52 
 53         String pkg;
 54 
 55         PackageKind(String pkg) {
 56             this.pkg = pkg;
 57         }
 58 
 59         @Override
 60         public String expand(String optParameter) {
 61             return this == NO_PKG ?
 62                 "" :
 63                 "package " + pkg + ";";
 64         }
 65 
 66         String getImportStat() {
 67             return this == NO_PKG ?
 68                 "" :
 69                 "import " + pkg + ".*;";
 70         }
 71     }
 72 
 73     enum SamKind implements ComboParameter {
 74         CLASS("public class Sam {  }"),
 75         ABSTACT_CLASS("public abstract class Sam {  }"),
 76         ANNOTATION("public @interface Sam {  }"),
 77         ENUM("public enum Sam { }"),
 78         INTERFACE("public interface Sam { \n #{METH1}; \n }");
 79 
 80         String sam_str;
 81 
 82         SamKind(String sam_str) {
 83             this.sam_str = sam_str;
 84         }
 85 
 86         @Override
 87         public String expand(String optParameter) {
 88             return sam_str;
 89         }
 90     }
 91 
 92     enum ModifierKind implements ComboParameter {
 93         PUBLIC("public"),
 94         PACKAGE("");
 95 
 96         String modifier_str;
 97 
 98         ModifierKind(String modifier_str) {
 99             this.modifier_str = modifier_str;
100         }
101 
102         @Override
103         public String expand(String optParameter) {
104             return modifier_str;
105         }
106     }
107 
108     enum TypeKind implements ComboParameter {
109         EXCEPTION("Exception"),
110         PKG_CLASS("PackageClass");
111 
112         String typeStr;
113 
114         TypeKind(String typeStr) {
115             this.typeStr = typeStr;
116         }
117 
118         @Override
119         public String expand(String optParameter) {
120             return typeStr;
121         }
122     }
123 
124     enum ExprKind implements ComboParameter {
125         LAMBDA("x -> null"),
126         MREF("this::m");
127 
128         String exprStr;
129 
130         ExprKind(String exprStr) {
131             this.exprStr = exprStr;
132         }
133 
134         @Override
135         public String expand(String optParameter) {
136             return exprStr;
137         }
138     }
139 
140     enum MethodKind implements ComboParameter {
141         NONE(""),
142         NON_GENERIC("public abstract #{RET} m(#{ARG} s) throws #{THROWN};"),
143         GENERIC("public abstract <X> #{RET} m(#{ARG} s) throws #{THROWN};");
144 
145         String methodTemplate;
146 
147         MethodKind(String methodTemplate) {
148             this.methodTemplate = methodTemplate;
149         }
150 
151         @Override
152         public String expand(String optParameter) {
153             return methodTemplate;
154         }
155     }
156 
157     public static void main(String[] args) throws Exception {
158         new ComboTestHelper<FunctionalInterfaceConversionTest>()
159                 .withDimension("PKG", (x, pkg) -> x.samPkg = pkg, PackageKind.values())
160                 .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
161                 .withDimension("CLAZZ", (x, sam) -> x.samKind = sam, SamKind.values())
162                 .withDimension("METH1", (x, meth) -> x.samMeth = meth, MethodKind.values())
163                 .withDimension("METH2", (x, meth) -> x.clientMeth = meth, MethodKind.values())
164                 .withDimension("RET", (x, ret) -> x.retType = ret, TypeKind.values())
165                 .withDimension("ARG", (x, arg) -> x.argType = arg, TypeKind.values())
166                 .withDimension("THROWN", (x, thrown) -> x.thrownType = thrown, TypeKind.values())
167                 .withDimension("EXPR", (x, expr) -> x.exprKind = expr, ExprKind.values())
168                 .run(FunctionalInterfaceConversionTest::new);
169     }
170 
171     PackageKind samPkg;
172     ModifierKind modKind;
173     SamKind samKind;
174     MethodKind samMeth;
175     MethodKind clientMeth;
176     TypeKind retType;
177     TypeKind argType;
178     TypeKind thrownType;
179     ExprKind exprKind;
180 
181     String samSource = "#{PKG} \n #{CLAZZ}";
182     String pkgClassSource = "#{PKG}\n #{MOD} class PackageClass extends Exception { }";
183     String clientSource = "#{IMP}\n abstract class Client { \n" +
184                            "  Sam s = #{EXPR};\n" +
185                            "  #{METH2} \n }";
186 
187     @Override
188     public void doWork() throws IOException {
189         newCompilationTask()
190                 .withSourceFromTemplate("Sam", samSource)
191                 .withSourceFromTemplate("PackageClass", pkgClassSource)
192                 .withSourceFromTemplate("Client", clientSource, this::importStmt)
193                 .analyze(this::check);
194     }
195 
196     ComboParameter importStmt(String name) {
197         switch (name) {
198             case "IMP": return new ComboParameter.Constant<>(samPkg.getImportStat());
199             default: return null;
200         }
201     }
202 
203     void check(Result<?> res) {
204         if (res.hasErrors() == checkSamConversion()) {
205             fail("Unexpected compilation result; " + res.compilationInfo());
206         }
207     }
208 
209     boolean checkSamConversion() {
210         if (samKind != SamKind.INTERFACE) {
211             //sam type must be an interface
212             return false;
213         } else if (samMeth == MethodKind.NONE) {
214             //interface must have at least a method
215             return false;
216         } else if (exprKind == ExprKind.LAMBDA &&
217                 samMeth != MethodKind.NON_GENERIC) {
218             //target method for lambda must be non-generic
219             return false;
220         } else if (exprKind == ExprKind.MREF &&
221                 clientMeth == MethodKind.NONE) {
222             return false;
223         } else if (samPkg != PackageKind.NO_PKG &&
224                 modKind != ModifierKind.PUBLIC &&
225                 (retType == TypeKind.PKG_CLASS ||
226                 argType == TypeKind.PKG_CLASS ||
227                 thrownType == TypeKind.PKG_CLASS)) {
228             //target must not contain inaccessible types
229             return false;
230         } else {
231             return true;
232         }
233     }
234 }