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