/* * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 8005166 8129962 * @summary Add support for static interface methods * Smoke test for static interface method hiding * @library /tools/javac/lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.comp * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper * @run main InterfaceMethodHidingTest */ import java.io.IOException; import combo.ComboInstance; import combo.ComboParameter; import combo.ComboTask.Result; import combo.ComboTestHelper; public class InterfaceMethodHidingTest extends ComboInstance<InterfaceMethodHidingTest> { enum SignatureKind implements ComboParameter { VOID_INTEGER("void m(Integer s)", false), STRING_INTEGER("String m(Integer s)", true), VOID_STRING("void m(String s)", false), STRING_STRING("String m(String s)", true); String sigStr; boolean needsReturn; SignatureKind(String sigStr, boolean needsReturn) { this.sigStr = sigStr; this.needsReturn = needsReturn; } boolean overrideEquivalentWith(SignatureKind s2) { switch (this) { case VOID_INTEGER: case STRING_INTEGER: return s2 == VOID_INTEGER || s2 == STRING_INTEGER; case VOID_STRING: case STRING_STRING: return s2 == VOID_STRING || s2 == STRING_STRING; default: throw new AssertionError("bad signature kind"); } } @Override public String expand(String optParameter) { return sigStr; } } enum MethodKind implements ComboParameter { VIRTUAL("#{SIG[#IDX]};"), STATIC("static #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"), DEFAULT("default #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"); String methTemplate; MethodKind(String methTemplate) { this.methTemplate = methTemplate; } boolean inherithed() { return this != STATIC; } static boolean overrides(MethodKind mk1, SignatureKind sk1, MethodKind mk2, SignatureKind sk2) { return sk1 == sk2 && mk2.inherithed() && mk1 != STATIC; } @Override public String expand(String optParameter) { return methTemplate.replaceAll("#IDX", optParameter); } } enum BodyExpr implements ComboParameter { NONE(""), THIS("Object o = this"); String bodyExprStr; BodyExpr(String bodyExprStr) { this.bodyExprStr = bodyExprStr; } boolean allowed(MethodKind mk) { return this == NONE || mk != MethodKind.STATIC; } @Override public String expand(String optParameter) { return bodyExprStr; } } public static void main(String... args) throws Exception { new ComboTestHelper<InterfaceMethodHidingTest>() .withArrayDimension("SIG", (x, sig, idx) -> x.signatureKinds[idx] = sig, 3, SignatureKind.values()) .withArrayDimension("BODY", (x, body, idx) -> x.bodyExprs[idx] = body, 3, BodyExpr.values()) .withArrayDimension("MET", (x, meth, idx) -> x.methodKinds[idx] = meth, 3, MethodKind.values()) .run(InterfaceMethodHidingTest::new); } MethodKind[] methodKinds = new MethodKind[3]; SignatureKind[] signatureKinds = new SignatureKind[3]; BodyExpr[] bodyExprs = new BodyExpr[3]; String template = "interface Sup {\n" + " default void sup() { }\n" + "}\n" + "interface A extends Sup {\n" + " #{MET[0].0}\n" + "}\n" + "interface B extends A, Sup {\n" + " #{MET[1].1}\n" + "}\n" + "interface C extends B, Sup {\n" + " #{MET[2].2}\n" + "}\n"; @Override public void doWork() throws IOException { check(newCompilationTask() .withOption("-XDallowStaticInterfaceMethods") .withSourceFromTemplate(template, this::returnExpr) .analyze()); } ComboParameter returnExpr(String name) { switch (name) { case "RET": return optParameter -> { int idx = new Integer(optParameter); return signatureKinds[idx].needsReturn ? "return null;" : "return;"; }; default: return null; } } void check(Result<?> res) { boolean errorExpected = !bodyExprs[0].allowed(methodKinds[0]) || !bodyExprs[1].allowed(methodKinds[1]) || !bodyExprs[2].allowed(methodKinds[2]); if (methodKinds[0].inherithed()) { errorExpected |= signatureKinds[1].overrideEquivalentWith(signatureKinds[0]) && !MethodKind.overrides(methodKinds[1], signatureKinds[1], methodKinds[0], signatureKinds[0]) || signatureKinds[2].overrideEquivalentWith(signatureKinds[0]) && !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[0], signatureKinds[0]); } if (methodKinds[1].inherithed()) { errorExpected |= signatureKinds[2].overrideEquivalentWith(signatureKinds[1]) && !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[1], signatureKinds[1]); } if (res.hasErrors() != errorExpected) { fail("Problem when compiling source:\n" + res.compilationInfo() + "\nfound error: " + res.hasErrors()); } } }