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 8005166 8129962
27  * @summary Add support for static interface methods
28  *          Smoke test for static interface method hiding
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 InterfaceMethodHidingTest
38  */
39 
40 import java.io.IOException;
41 
42 import combo.ComboInstance;
43 import combo.ComboParameter;
44 import combo.ComboTask.Result;
45 import combo.ComboTestHelper;
46 
47 public class InterfaceMethodHidingTest extends ComboInstance<InterfaceMethodHidingTest> {
48 
49     enum SignatureKind implements ComboParameter {
50         VOID_INTEGER("void m(Integer s)", false),
51         STRING_INTEGER("String m(Integer s)", true),
52         VOID_STRING("void m(String s)", false),
53         STRING_STRING("String m(String s)", true);
54 
55         String sigStr;
56         boolean needsReturn;
57 
SignatureKind(String sigStr, boolean needsReturn)58         SignatureKind(String sigStr, boolean needsReturn) {
59             this.sigStr = sigStr;
60             this.needsReturn = needsReturn;
61         }
62 
overrideEquivalentWith(SignatureKind s2)63         boolean overrideEquivalentWith(SignatureKind s2) {
64             switch (this) {
65                 case VOID_INTEGER:
66                 case STRING_INTEGER:
67                     return s2 == VOID_INTEGER || s2 == STRING_INTEGER;
68                 case VOID_STRING:
69                 case STRING_STRING:
70                     return s2 == VOID_STRING || s2 == STRING_STRING;
71                 default:
72                     throw new AssertionError("bad signature kind");
73             }
74         }
75 
76         @Override
expand(String optParameter)77         public String expand(String optParameter) {
78             return sigStr;
79         }
80     }
81 
82     enum MethodKind implements ComboParameter {
83         VIRTUAL("#{SIG[#IDX]};"),
84         STATIC("static #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"),
85         DEFAULT("default #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }");
86 
87         String methTemplate;
88 
MethodKind(String methTemplate)89         MethodKind(String methTemplate) {
90             this.methTemplate = methTemplate;
91         }
92 
inherithed()93         boolean inherithed() {
94             return this != STATIC;
95         }
96 
overrides(MethodKind mk1, SignatureKind sk1, MethodKind mk2, SignatureKind sk2)97         static boolean overrides(MethodKind mk1, SignatureKind sk1, MethodKind mk2, SignatureKind sk2) {
98             return sk1 == sk2 &&
99                     mk2.inherithed() &&
100                     mk1 != STATIC;
101         }
102 
103         @Override
expand(String optParameter)104         public String expand(String optParameter) {
105             return methTemplate.replaceAll("#IDX", optParameter);
106         }
107     }
108 
109     enum BodyExpr implements ComboParameter {
110         NONE(""),
111         THIS("Object o = this");
112 
113         String bodyExprStr;
114 
BodyExpr(String bodyExprStr)115         BodyExpr(String bodyExprStr) {
116             this.bodyExprStr = bodyExprStr;
117         }
118 
allowed(MethodKind mk)119         boolean allowed(MethodKind mk) {
120             return this == NONE ||
121                     mk != MethodKind.STATIC;
122         }
123 
124         @Override
expand(String optParameter)125         public String expand(String optParameter) {
126             return bodyExprStr;
127         }
128     }
129 
main(String... args)130     public static void main(String... args) throws Exception {
131         new ComboTestHelper<InterfaceMethodHidingTest>()
132                 .withArrayDimension("SIG", (x, sig, idx) -> x.signatureKinds[idx] = sig, 3, SignatureKind.values())
133                 .withArrayDimension("BODY", (x, body, idx) -> x.bodyExprs[idx] = body, 3, BodyExpr.values())
134                 .withArrayDimension("MET", (x, meth, idx) -> x.methodKinds[idx] = meth, 3, MethodKind.values())
135                 .run(InterfaceMethodHidingTest::new);
136     }
137 
138     MethodKind[] methodKinds = new MethodKind[3];
139     SignatureKind[] signatureKinds = new SignatureKind[3];
140     BodyExpr[] bodyExprs = new BodyExpr[3];
141 
142     String template = "interface Sup {\n" +
143                           "   default void sup() { }\n" +
144                           "}\n" +
145                           "interface A extends Sup {\n" +
146                           "   #{MET[0].0}\n" +
147                           "}\n" +
148                           "interface B extends A, Sup {\n" +
149                           "   #{MET[1].1}\n" +
150                           "}\n" +
151                           "interface C extends B, Sup {\n" +
152                           "   #{MET[2].2}\n" +
153                           "}\n";
154 
155     @Override
doWork()156     public void doWork() throws IOException {
157         newCompilationTask()
158                 .withOption("-XDallowStaticInterfaceMethods")
159                 .withSourceFromTemplate(template, this::returnExpr)
160                 .analyze(this::check);
161     }
162 
returnExpr(String name)163     ComboParameter returnExpr(String name) {
164         switch (name) {
165             case "RET":
166                 return optParameter -> {
167                     int idx = new Integer(optParameter);
168                     return signatureKinds[idx].needsReturn ? "return null;" : "return;";
169                 };
170             default:
171                 return null;
172         }
173     }
174 
check(Result<?> res)175     void check(Result<?> res) {
176         boolean errorExpected = !bodyExprs[0].allowed(methodKinds[0]) ||
177                 !bodyExprs[1].allowed(methodKinds[1]) ||
178                 !bodyExprs[2].allowed(methodKinds[2]);
179 
180         if (methodKinds[0].inherithed()) {
181             errorExpected |= signatureKinds[1].overrideEquivalentWith(signatureKinds[0]) &&
182                     !MethodKind.overrides(methodKinds[1], signatureKinds[1], methodKinds[0], signatureKinds[0]) ||
183                     signatureKinds[2].overrideEquivalentWith(signatureKinds[0]) &&
184                     !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[0], signatureKinds[0]);
185         }
186 
187         if (methodKinds[1].inherithed()) {
188             errorExpected |= signatureKinds[2].overrideEquivalentWith(signatureKinds[1]) &&
189                     !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[1], signatureKinds[1]);
190         }
191 
192         if (res.hasErrors() != errorExpected) {
193             fail("Problem when compiling source:\n" + res.compilationInfo() +
194                     "\nfound error: " + res.hasErrors());
195         }
196     }
197 }
198