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