diff -r 000000000000 -r 959103a6100f test/tools/javac/cast/intersection/IntersectionTypeCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Wed Apr 27 01:34:52 2016 +0800 @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2012, 2013, 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 8002099 8006694 + * @summary Add support for intersection types in cast expression + * temporarily workaround combo tests are causing time out in several platforms + * @library ../../lib + * @build JavacTestingAbstractThreadedTest + * @run main/othervm/timeout=360 IntersectionTypeCastTest + */ + +// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) +// see JDK-8006746 + +import java.net.URI; +import java.util.Arrays; +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; + +public class IntersectionTypeCastTest + extends JavacTestingAbstractThreadedTest + implements Runnable { + + interface Type { + boolean subtypeOf(Type that); + String asString(); + boolean isClass(); + boolean isInterface(); + } + + enum InterfaceKind implements Type { + A("interface A { }\n", "A", null), + B("interface B { }\n", "B", null), + C("interface C extends A { }\n", "C", A); + + String declStr; + String typeStr; + InterfaceKind superInterface; + + InterfaceKind(String declStr, String typeStr, + InterfaceKind superInterface) { + this.declStr = declStr; + this.typeStr = typeStr; + this.superInterface = superInterface; + } + + @Override + public boolean subtypeOf(Type that) { + return this == that || superInterface == that || + that == ClassKind.OBJECT; + } + + @Override + public String asString() { + return typeStr; + } + + @Override + public boolean isClass() { + return false; + } + + @Override + public boolean isInterface() { + return true; + } + } + + enum ClassKind implements Type { + OBJECT(null, "Object"), + CA("#M class CA implements A { }\n", "CA", + InterfaceKind.A), + CB("#M class CB implements B { }\n", "CB", + InterfaceKind.B), + CAB("#M class CAB implements A, B { }\n", "CAB", + InterfaceKind.A, InterfaceKind.B), + CC("#M class CC implements C { }\n", "CC", + InterfaceKind.C, InterfaceKind.A), + CCA("#M class CCA implements C, A { }\n", "CCA", + InterfaceKind.C, InterfaceKind.A), + CCB("#M class CCB implements C, B { }\n", "CCB", + InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), + CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", + InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); + + String declTemplate; + String typeStr; + List superInterfaces; + + ClassKind(String declTemplate, String typeStr, + InterfaceKind... superInterfaces) { + this.declTemplate = declTemplate; + this.typeStr = typeStr; + this.superInterfaces = List.from(superInterfaces); + } + + String getDecl(ModifierKind mod) { + return declTemplate != null ? + declTemplate.replaceAll("#M", mod.modStr) : + ""; + } + + @Override + public boolean subtypeOf(Type that) { + return this == that || superInterfaces.contains(that) || + that == OBJECT; + } + + @Override + public String asString() { + return typeStr; + } + + @Override + public boolean isClass() { + return true; + } + + @Override + public boolean isInterface() { + return false; + } + } + + enum ModifierKind { + NONE(""), + FINAL("final"); + + String modStr; + + ModifierKind(String modStr) { + this.modStr = modStr; + } + } + + enum CastKind { + CLASS("(#C)", 0), + INTERFACE("(#I0)", 1), + INTERSECTION2("(#C & #I0)", 1), + INTERSECTION3("(#C & #I0 & #I1)", 2); + //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3); + + String castTemplate; + int interfaceBounds; + + CastKind(String castTemplate, int interfaceBounds) { + this.castTemplate = castTemplate; + this.interfaceBounds = interfaceBounds; + } + } + + static class CastInfo { + CastKind kind; + Type[] types; + + CastInfo(CastKind kind, Type... types) { + this.kind = kind; + this.types = types; + } + + String getCast() { + String temp = kind.castTemplate.replaceAll("#C", + types[0].asString()); + for (int i = 0; i < kind.interfaceBounds ; i++) { + temp = temp.replace(String.format("#I%d", i), + types[i + 1].asString()); + } + return temp; + } + + boolean hasDuplicateTypes() { + for (int i = 0 ; i < types.length ; i++) { + for (int j = 0 ; j < types.length ; j++) { + if (i != j && types[i] == types[j]) { + return true; + } + } + } + return false; + } + + boolean compatibleWith(ModifierKind mod, CastInfo that) { + for (Type t1 : types) { + for (Type t2 : that.types) { + boolean compat = + t1.subtypeOf(t2) || + t2.subtypeOf(t1) || + (t1.isInterface() && t2.isInterface()) || //side-cast (1) + (mod == ModifierKind.NONE && + (t1.isInterface() != t2.isInterface())); //side-cast (2) + if (!compat) return false; + } + } + return true; + } + } + + public static void main(String... args) throws Exception { + for (ModifierKind mod : ModifierKind.values()) { + for (CastInfo cast1 : allCastInfo()) { + for (CastInfo cast2 : allCastInfo()) { + pool.execute( + new IntersectionTypeCastTest(mod, cast1, cast2)); + } + } + } + checkAfterExec(); + } + + static List allCastInfo() { + ListBuffer buf = new ListBuffer<>(); + for (CastKind kind : CastKind.values()) { + for (ClassKind clazz : ClassKind.values()) { + if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) { + continue; + } else if (kind.interfaceBounds == 0) { + buf.append(new CastInfo(kind, clazz)); + continue; + } else { + for (InterfaceKind intf1 : InterfaceKind.values()) { + if (kind.interfaceBounds == 1) { + buf.append(new CastInfo(kind, clazz, intf1)); + continue; + } else { + for (InterfaceKind intf2 : InterfaceKind.values()) { + if (kind.interfaceBounds == 2) { + buf.append( + new CastInfo(kind, clazz, intf1, intf2)); + continue; + } else { + for (InterfaceKind intf3 : InterfaceKind.values()) { + buf.append( + new CastInfo(kind, clazz, intf1, + intf2, intf3)); + continue; + } + } + } + } + } + } + } + } + return buf.toList(); + } + + ModifierKind mod; + CastInfo cast1, cast2; + JavaSource source; + DiagnosticChecker diagChecker; + + IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) { + this.mod = mod; + this.cast1 = cast1; + this.cast2 = cast2; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + @Override + public void run() { + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + + JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, + null, null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thrown when compiling the following code:\n" + + source.getCharContent(true)); + } + check(); + } + + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "class Test {\n" + + " void test() {\n" + + " Object o = #C1#C2null;\n" + + " } }"; + + String source = ""; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + for (ClassKind ck : ClassKind.values()) { + source += ck.getDecl(mod); + } + for (InterfaceKind ik : InterfaceKind.values()) { + source += ik.declStr; + } + source += bodyTemplate.replaceAll("#C1", cast1.getCast()). + replaceAll("#C2", cast2.getCast()); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void check() { + checkCount.incrementAndGet(); + + boolean errorExpected = cast1.hasDuplicateTypes() || + cast2.hasDuplicateTypes(); + + errorExpected |= !cast2.compatibleWith(mod, cast1); + + if (errorExpected != diagChecker.errorFound) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker + implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } + +}