1 /*
  2  * Copyright (c) 2011, 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 7046778 8006694 8129962
 27  * @summary Project Coin: problem with diamond and member inner classes
 28  *  temporarily workaround combo tests are causing time out in several platforms
 29  * @enablePreview
 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  * @compile -Xlint:all DiamondAndInnerClassTest.java
 36  * @run main DiamondAndInnerClassTest
 37  */
 38 
 39 import java.io.IOException;
 40 import java.util.Arrays;
 41 
 42 import combo.ComboTestHelper;
 43 import combo.ComboInstance;
 44 import combo.ComboParameter;
 45 import combo.ComboTask.Result;
 46 
 47 public class DiamondAndInnerClassTest extends ComboInstance<DiamondAndInnerClassTest> {
 48 
 49     enum TypeArgumentKind implements ComboParameter {
 50         NONE(""),
 51         STRING("<String>"),
 52         INTEGER("<Integer>"),
 53         DIAMOND("<>");
 54 
 55         String typeargStr;
 56 
 57         TypeArgumentKind(String typeargStr) {
 58             this.typeargStr = typeargStr;
 59         }
 60 
 61         boolean compatible(TypeArgumentKind that) {
 62             switch (this) {
 63                 case NONE: return true;
 64                 case STRING: return that != INTEGER;
 65                 case INTEGER: return that != STRING;
 66                 default: throw new AssertionError("Unexpected decl kind: " + this);
 67             }
 68         }
 69 
 70         boolean compatible(ArgumentKind that) {
 71             switch (this) {
 72                 case NONE: return true;
 73                 case STRING: return that == ArgumentKind.STRING;
 74                 case INTEGER: return that == ArgumentKind.INTEGER;
 75                 default: throw new AssertionError("Unexpected decl kind: " + this);
 76             }
 77         }
 78 
 79         @Override
 80         public String expand(String optParameter) {
 81             return typeargStr;
 82         }
 83     }
 84 
 85     enum ArgumentKind implements ComboParameter {
 86         OBJECT("(Object)null"),
 87         STRING("(String)null"),
 88         INTEGER("(Integer)null");
 89 
 90         String argStr;
 91 
 92         ArgumentKind(String argStr) {
 93             this.argStr = argStr;
 94         }
 95 
 96         @Override
 97         public String expand(String optParameter) {
 98             return argStr;
 99         }
100     }
101 
102     enum TypeQualifierArity implements ComboParameter {
103         ONE(1, "A1#{TA#IDX[0]}"),
104         TWO(2, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}"),
105         THREE(3, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}.A3#{TA#IDX[2]}");
106 
107         int n;
108         String qualifierStr;
109 
110         TypeQualifierArity(int n, String qualifierStr) {
111             this.n = n;
112             this.qualifierStr = qualifierStr;
113         }
114 
115         @Override
116         public String expand(String optParameter) {
117             return qualifierStr.replaceAll("#IDX", optParameter);
118         }
119     }
120 
121     enum InnerClassDeclArity implements ComboParameter {
122         ONE(1, "class A1<X> { A1(X x1) { } #{BODY} }"),
123         TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { }  #{BODY} } }"),
124         THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #{BODY} } } }");
125 
126         int n;
127         String classDeclStr;
128 
129         InnerClassDeclArity(int n, String classDeclStr) {
130             this.n = n;
131             this.classDeclStr = classDeclStr;
132         }
133 
134         @Override
135         public String expand(String optParameter) {
136             return classDeclStr;
137         }
138     }
139 
140     enum ArgumentListArity implements ComboParameter {
141         ONE(1, "(#{A[0]})"),
142         TWO(2, "(#{A[0]},#{A[1]})"),
143         THREE(3, "(#{A[0]},#{A[1]},#{A[2]})");
144 
145         int n;
146         String argListStr;
147 
148         ArgumentListArity(int n, String argListStr) {
149             this.n = n;
150             this.argListStr = argListStr;
151         }
152 
153         @Override
154         public String expand(String optParameter) {
155             return argListStr.replaceAll("#IDX", optParameter);
156         }
157     }
158 
159     public static void main(String... args) throws Exception {
160         new ComboTestHelper<DiamondAndInnerClassTest>()
161                 .withFilter(DiamondAndInnerClassTest::rareTypesFilter)
162                 .withFilter(DiamondAndInnerClassTest::noDiamondOnDecl)
163                 .withFilter(DiamondAndInnerClassTest::noDiamondOnIntermediateTypes)
164                 .withFilter(DiamondAndInnerClassTest::arityMismatch)
165                 .withFilter(DiamondAndInnerClassTest::redundantFilter)
166                 .withDimension("BODY", new ComboParameter.Constant<>("#{D.1} res = new #{S.2}#{AL};"))
167                 .withDimension("DECL", (x, arity) -> x.innerClassDeclArity = arity, InnerClassDeclArity.values())
168                 .withDimension("D", (x, arity) -> x.declArity = arity, TypeQualifierArity.values())
169                 .withDimension("S", (x, arity) -> x.siteArity = arity, TypeQualifierArity.values())
170                 .withDimension("AL", (x, alist) -> x.argumentListArity = alist, ArgumentListArity.values())
171                 .withArrayDimension("TA1", (x, targs, idx) -> x.declTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values())
172                 .withArrayDimension("TA2", (x, targs, idx) -> x.siteTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values())
173                 .withArrayDimension("A", (x, argsk, idx) -> x.argumentKinds[idx] = argsk, 3, ArgumentKind.values())
174                 .run(DiamondAndInnerClassTest::new);
175     }
176 
177     InnerClassDeclArity innerClassDeclArity;
178     TypeQualifierArity declArity;
179     TypeQualifierArity siteArity;
180     TypeArgumentKind[] declTypeArgumentKinds = new TypeArgumentKind[3];
181     TypeArgumentKind[] siteTypeArgumentKinds = new TypeArgumentKind[3];
182     ArgumentKind[] argumentKinds = new ArgumentKind[3];
183     ArgumentListArity argumentListArity;
184 
185     boolean rareTypesFilter() {
186         for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) {
187             boolean isRaw = types[0] == TypeArgumentKind.NONE;
188             for (int i = 1; i < innerClassDeclArity.n; i++) {
189                 if (isRaw != (types[i] == TypeArgumentKind.NONE)) {
190                     return false;
191                 }
192             }
193         }
194         return true;
195     }
196 
197     boolean noDiamondOnDecl() {
198         for (int i = 0; i < innerClassDeclArity.n; i++) {
199             if (declTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
200                 return false;
201             }
202         }
203         return true;
204     }
205 
206     boolean noDiamondOnIntermediateTypes() {
207         for (int i = 0; i < (innerClassDeclArity.n - 1); i++) {
208             if (siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
209                 return false;
210             }
211         }
212         return true;
213     }
214 
215     boolean redundantFilter() {
216         for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) {
217             for (int i = innerClassDeclArity.n; i < types.length; i++) {
218                 if (types[i].ordinal() != 0) {
219                     return false;
220                 }
221             }
222         }
223         for (int i = innerClassDeclArity.n; i < argumentKinds.length; i++) {
224             if (argumentKinds[i].ordinal() != 0) {
225                 return false;
226             }
227         }
228         return true;
229     }
230 
231     boolean arityMismatch() {
232         return argumentListArity.n == innerClassDeclArity.n &&
233                 siteArity.n == innerClassDeclArity.n &&
234                 declArity.n == innerClassDeclArity.n;
235     }
236 
237     @Override
238     public void doWork() throws IOException {
239         newCompilationTask()
240                 .withSourceFromTemplate("#{DECL}")
241                 .analyze(this::check);
242     }
243 
244     void check(Result<?> res) {
245         boolean errorExpected = false;
246 
247         TypeArgumentKind[] expectedArgKinds =
248                 new TypeArgumentKind[innerClassDeclArity.n];
249 
250         for (int i = 0 ; i < innerClassDeclArity.n ; i++) {
251             if (!declTypeArgumentKinds[i].compatible(siteTypeArgumentKinds[i])) {
252                 errorExpected = true;
253                 break;
254             }
255             expectedArgKinds[i] = siteTypeArgumentKinds[i] ==
256                     TypeArgumentKind.DIAMOND ?
257                 declTypeArgumentKinds[i] : siteTypeArgumentKinds[i];
258         }
259 
260         if (!errorExpected) {
261             for (int i = 0 ; i < innerClassDeclArity.n ; i++) {
262                 if (!expectedArgKinds[i].compatible(argumentKinds[i])) {
263                     errorExpected = true;
264                     break;
265                 }
266             }
267         }
268 
269         if (errorExpected != res.hasErrors()) {
270             fail("invalid diagnostics for source:\n" +
271                 res.compilationInfo() +
272                 "\nFound error: " + res.hasErrors() +
273                 "\nExpected error: " + errorExpected);
274         }
275     }
276 }