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