TestDefaultSuperCall.java revision 3019:176472b94f2e
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 7192246 8006694 8129962
27 * @summary Automatic test for checking correctness of default super/this resolution
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 * @run main TestDefaultSuperCall
38 */
39
40import java.io.IOException;
41import java.util.ArrayList;
42import java.util.List;
43
44import combo.ComboInstance;
45import combo.ComboParameter;
46import combo.ComboTask.Result;
47import combo.ComboTestHelper;
48
49public class TestDefaultSuperCall extends ComboInstance<TestDefaultSuperCall> {
50
51    enum InterfaceKind implements ComboParameter {
52        DEFAULT("interface A extends B { default void m() { } }"),
53        ABSTRACT("interface A extends B { void m(); }"),
54        NONE("interface A extends B { }");
55
56        String interfaceStr;
57
58        InterfaceKind(String interfaceStr) {
59            this.interfaceStr = interfaceStr;
60        }
61
62        boolean methodDefined() {
63            return this == DEFAULT;
64        }
65
66        @Override
67        public String expand(String optParameter) {
68            return interfaceStr;
69        }
70    }
71
72    enum PruneKind implements ComboParameter {
73        NO_PRUNE("interface C { }"),
74        PRUNE("interface C extends A { }");
75
76        boolean methodDefined(InterfaceKind ik) {
77            return this == PRUNE &&
78                    ik.methodDefined();
79        }
80
81        String interfaceStr;
82
83        PruneKind(String interfaceStr) {
84            this.interfaceStr = interfaceStr;
85        }
86
87        @Override
88        public String expand(String optParameter) {
89            return interfaceStr;
90        }
91    }
92
93    enum QualifierKind implements ComboParameter {
94        DIRECT_1("C"),
95        DIRECT_2("A"),
96        INDIRECT("B"),
97        UNRELATED("E"),
98        ENCLOSING_1("name0"),
99        ENCLOSING_2("name1");
100
101        String qualifierStr;
102
103        QualifierKind(String qualifierStr) {
104            this.qualifierStr = qualifierStr;
105        }
106
107        boolean isEnclosing() {
108            return this == ENCLOSING_1 ||
109                    this == ENCLOSING_2;
110        }
111
112        boolean allowSuperCall(InterfaceKind ik, PruneKind pk) {
113            switch (this) {
114                case DIRECT_1:
115                    return pk.methodDefined(ik);
116                case DIRECT_2:
117                    return ik.methodDefined() && pk == PruneKind.NO_PRUNE;
118                default:
119                    return false;
120            }
121        }
122
123        @Override
124        public String expand(String optParameter) {
125            return qualifierStr;
126        }
127    }
128
129    enum ExprKind implements ComboParameter {
130        THIS("this"),
131        SUPER("super");
132
133        String exprStr;
134
135        ExprKind(String exprStr) {
136            this.exprStr = exprStr;
137        }
138
139        @Override
140        public String expand(String optParameter) {
141            return exprStr;
142        }
143    }
144
145    enum ElementKind implements ComboParameter {
146        INTERFACE("interface name#CURR { #BODY }", true),
147        INTERFACE_EXTENDS("interface name#CURR extends A, C { #BODY }", true),
148        CLASS("class name#CURR { #BODY }", false),
149        CLASS_EXTENDS("abstract class name#CURR implements A, C { #BODY }", false),
150        STATIC_CLASS("static class name#CURR { #BODY }", true),
151        STATIC_CLASS_EXTENDS("abstract static class name#CURR implements A, C { #BODY }", true),
152        ANON_CLASS("new Object() { #BODY };", false),
153        METHOD("void test() { #BODY }", false),
154        STATIC_METHOD("static void test() { #BODY }", true),
155        DEFAULT_METHOD("default void test() { #BODY }", false);
156
157        String templateDecl;
158        boolean isStatic;
159
160        ElementKind(String templateDecl, boolean isStatic) {
161            this.templateDecl = templateDecl;
162            this.isStatic = isStatic;
163        }
164
165        boolean isClassDecl() {
166            switch(this) {
167                case METHOD:
168                case STATIC_METHOD:
169                case DEFAULT_METHOD:
170                    return false;
171                default:
172                    return true;
173            }
174        }
175
176        boolean isAllowedEnclosing(ElementKind ek, boolean isTop) {
177            switch (this) {
178                case CLASS:
179                case CLASS_EXTENDS:
180                    //class is implicitly static inside interface, so skip this combo
181                    return ek.isClassDecl() &&
182                            ek != INTERFACE && ek != INTERFACE_EXTENDS;
183                case ANON_CLASS:
184                    return !ek.isClassDecl();
185                case METHOD:
186                    return ek == CLASS || ek == CLASS_EXTENDS ||
187                            ek == STATIC_CLASS || ek == STATIC_CLASS_EXTENDS ||
188                            ek == ANON_CLASS;
189                case INTERFACE:
190                case INTERFACE_EXTENDS:
191                case STATIC_CLASS:
192                case STATIC_CLASS_EXTENDS:
193                case STATIC_METHOD:
194                    return (isTop && (ek == CLASS || ek == CLASS_EXTENDS)) ||
195                            ek == STATIC_CLASS || ek == STATIC_CLASS_EXTENDS;
196                case DEFAULT_METHOD:
197                    return ek == INTERFACE || ek == INTERFACE_EXTENDS;
198                default:
199                    throw new AssertionError("Bad enclosing element kind" + this);
200            }
201        }
202
203        boolean isAllowedTop() {
204            switch (this) {
205                case CLASS:
206                case CLASS_EXTENDS:
207                case INTERFACE:
208                case INTERFACE_EXTENDS:
209                    return true;
210                default:
211                    return false;
212            }
213        }
214
215        boolean hasSuper() {
216            return this == INTERFACE_EXTENDS ||
217                    this == STATIC_CLASS_EXTENDS ||
218                    this == CLASS_EXTENDS;
219        }
220
221        @Override
222        public String expand(String optParameter) {
223            int nextDepth = new Integer(optParameter) + 1;
224            String replStr = (nextDepth <= 4) ?
225                    String.format("#{ELEM[%d].%d}", nextDepth, nextDepth) :
226                    "#{QUAL}.#{EXPR}.#{METH}();";
227            return templateDecl
228                    .replaceAll("#CURR", optParameter)
229                    .replaceAll("#BODY", replStr);
230        }
231    }
232
233    static class Shape {
234
235        List<ElementKind> enclosingElements;
236        List<String> enclosingNames;
237        List<String> elementsWithMethod;
238
239        Shape(ElementKind... elements) {
240            enclosingElements = new ArrayList<>();
241            enclosingNames = new ArrayList<>();
242            elementsWithMethod = new ArrayList<>();
243            int count = 0;
244            String prevName = null;
245            for (ElementKind ek : elements) {
246                String name = "name"+count++;
247                if (ek.isStatic) {
248                    enclosingElements = new ArrayList<>();
249                    enclosingNames = new ArrayList<>();
250                }
251                if (ek.isClassDecl()) {
252                    enclosingElements.add(ek);
253                    enclosingNames.add(name);
254                } else {
255                    elementsWithMethod.add(prevName);
256                }
257                prevName = name;
258            }
259        }
260    }
261
262    public static void main(String... args) throws Exception {
263        new ComboTestHelper<TestDefaultSuperCall>()
264                .withFilter(TestDefaultSuperCall::filterBadTopElement)
265                .withFilter(TestDefaultSuperCall::filterBadIntermediateElement)
266                .withFilter(TestDefaultSuperCall::filterBadTerminalElement)
267                .withDimension("INTF1", (x, ik) -> x.ik = ik, InterfaceKind.values())
268                .withDimension("INTF2", (x, pk) -> x.pk = pk, PruneKind.values())
269                .withArrayDimension("ELEM", (x, elem, idx) -> x.elements[idx] = elem, 5, ElementKind.values())
270                .withDimension("QUAL", (x, qk) -> x.qk = qk, QualifierKind.values())
271                .withDimension("EXPR", (x, ek) -> x.ek = ek, ExprKind.values())
272                .run(TestDefaultSuperCall::new);
273    }
274
275    InterfaceKind ik;
276    PruneKind pk;
277    ElementKind[] elements = new ElementKind[5];
278    QualifierKind qk;
279    ExprKind ek;
280
281    boolean filterBadTopElement() {
282        return elements[0].isAllowedTop();
283    }
284
285    boolean filterBadIntermediateElement() {
286        for (int i = 1 ; i < 4 ; i++) {
287            if (!elements[i].isAllowedEnclosing(elements[i - 1], i == 1)) {
288                return false;
289            }
290        }
291        return true;
292    }
293
294    boolean filterBadTerminalElement() {
295        return elements[4].isAllowedEnclosing(elements[3], false) && !elements[4].isClassDecl();
296    }
297
298    String template = "interface E {}\n" +
299                      "interface B { }\n" +
300                      "#{INTF1}\n" +
301                      "#{INTF2}\n" +
302                      "#{ELEM[0].0}";
303
304    @Override
305    public void doWork() throws IOException {
306        check(newCompilationTask()
307                .withSourceFromTemplate(template, this::methodName)
308                .analyze());
309    }
310
311    ComboParameter methodName(String parameterName) {
312        switch (parameterName) {
313            case "METH":
314                String methodName = ek == ExprKind.THIS ? "test" : "m";
315                return new ComboParameter.Constant<String>(methodName);
316            default:
317                return null;
318        }
319    }
320
321    void check(Result<?> res) {
322        Shape sh = new Shape(elements);
323
324        boolean errorExpected = false;
325
326        boolean badEnclosing = false;
327        boolean badThis = false;
328        boolean badSuper = false;
329
330        if (qk == QualifierKind.ENCLOSING_1 &&
331                sh.enclosingNames.size() < 1) {
332            errorExpected |= true;
333            badEnclosing = true;
334        }
335
336        if (qk == QualifierKind.ENCLOSING_2 &&
337                sh.enclosingNames.size() < 2) {
338            errorExpected |= true;
339            badEnclosing = true;
340        }
341
342        if (ek == ExprKind.THIS) {
343            boolean found = false;
344            for (int i = 0; i < sh.enclosingElements.size(); i++) {
345                if (sh.enclosingElements.get(i) == ElementKind.ANON_CLASS) continue;
346                if (sh.enclosingNames.get(i).equals(qk.qualifierStr)) {
347                    found = sh.elementsWithMethod.contains(sh.enclosingNames.get(i));
348                    break;
349                }
350            }
351            errorExpected |= !found;
352            if (!found) {
353                badThis = true;
354            }
355        }
356
357        if (ek == ExprKind.SUPER) {
358
359            int lastIdx = sh.enclosingElements.size() - 1;
360            boolean found = lastIdx == -1 ? false :
361                    sh.enclosingElements.get(lastIdx).hasSuper() &&
362                    qk.allowSuperCall(ik, pk);
363
364            errorExpected |= !found;
365            if (!found) {
366                badSuper = true;
367            }
368        }
369
370        if (res.hasErrors() != errorExpected) {
371            fail("Problem when compiling source:\n" +
372                    res.compilationInfo() +
373                    "\nenclosingElems: " + sh.enclosingElements +
374                    "\nenclosingNames: " + sh.enclosingNames +
375                    "\nelementsWithMethod: " + sh.elementsWithMethod +
376                    "\nbad encl: " + badEnclosing +
377                    "\nbad this: " + badThis +
378                    "\nbad super: " + badSuper +
379                    "\nqual kind: " + qk +
380                    "\nfound error: " + res.hasErrors());
381        }
382    }
383}
384