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