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