1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,359 @@ 1.4 +/* 1.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + */ 1.26 + 1.27 +/* 1.28 + * @test 1.29 + * @bug 8002099 8006694 1.30 + * @summary Add support for intersection types in cast expression 1.31 + * temporarily workaround combo tests are causing time out in several platforms 1.32 + * @library ../../lib 1.33 + * @build JavacTestingAbstractThreadedTest 1.34 + * @run main/othervm/timeout=360 IntersectionTypeCastTest 1.35 + */ 1.36 + 1.37 +// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) 1.38 +// see JDK-8006746 1.39 + 1.40 +import java.net.URI; 1.41 +import java.util.Arrays; 1.42 +import javax.tools.Diagnostic; 1.43 +import javax.tools.JavaCompiler; 1.44 +import javax.tools.JavaFileObject; 1.45 +import javax.tools.SimpleJavaFileObject; 1.46 +import javax.tools.ToolProvider; 1.47 + 1.48 +import com.sun.source.util.JavacTask; 1.49 +import com.sun.tools.javac.util.List; 1.50 +import com.sun.tools.javac.util.ListBuffer; 1.51 + 1.52 +public class IntersectionTypeCastTest 1.53 + extends JavacTestingAbstractThreadedTest 1.54 + implements Runnable { 1.55 + 1.56 + interface Type { 1.57 + boolean subtypeOf(Type that); 1.58 + String asString(); 1.59 + boolean isClass(); 1.60 + boolean isInterface(); 1.61 + } 1.62 + 1.63 + enum InterfaceKind implements Type { 1.64 + A("interface A { }\n", "A", null), 1.65 + B("interface B { }\n", "B", null), 1.66 + C("interface C extends A { }\n", "C", A); 1.67 + 1.68 + String declStr; 1.69 + String typeStr; 1.70 + InterfaceKind superInterface; 1.71 + 1.72 + InterfaceKind(String declStr, String typeStr, 1.73 + InterfaceKind superInterface) { 1.74 + this.declStr = declStr; 1.75 + this.typeStr = typeStr; 1.76 + this.superInterface = superInterface; 1.77 + } 1.78 + 1.79 + @Override 1.80 + public boolean subtypeOf(Type that) { 1.81 + return this == that || superInterface == that || 1.82 + that == ClassKind.OBJECT; 1.83 + } 1.84 + 1.85 + @Override 1.86 + public String asString() { 1.87 + return typeStr; 1.88 + } 1.89 + 1.90 + @Override 1.91 + public boolean isClass() { 1.92 + return false; 1.93 + } 1.94 + 1.95 + @Override 1.96 + public boolean isInterface() { 1.97 + return true; 1.98 + } 1.99 + } 1.100 + 1.101 + enum ClassKind implements Type { 1.102 + OBJECT(null, "Object"), 1.103 + CA("#M class CA implements A { }\n", "CA", 1.104 + InterfaceKind.A), 1.105 + CB("#M class CB implements B { }\n", "CB", 1.106 + InterfaceKind.B), 1.107 + CAB("#M class CAB implements A, B { }\n", "CAB", 1.108 + InterfaceKind.A, InterfaceKind.B), 1.109 + CC("#M class CC implements C { }\n", "CC", 1.110 + InterfaceKind.C, InterfaceKind.A), 1.111 + CCA("#M class CCA implements C, A { }\n", "CCA", 1.112 + InterfaceKind.C, InterfaceKind.A), 1.113 + CCB("#M class CCB implements C, B { }\n", "CCB", 1.114 + InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), 1.115 + CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", 1.116 + InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); 1.117 + 1.118 + String declTemplate; 1.119 + String typeStr; 1.120 + List<InterfaceKind> superInterfaces; 1.121 + 1.122 + ClassKind(String declTemplate, String typeStr, 1.123 + InterfaceKind... superInterfaces) { 1.124 + this.declTemplate = declTemplate; 1.125 + this.typeStr = typeStr; 1.126 + this.superInterfaces = List.from(superInterfaces); 1.127 + } 1.128 + 1.129 + String getDecl(ModifierKind mod) { 1.130 + return declTemplate != null ? 1.131 + declTemplate.replaceAll("#M", mod.modStr) : 1.132 + ""; 1.133 + } 1.134 + 1.135 + @Override 1.136 + public boolean subtypeOf(Type that) { 1.137 + return this == that || superInterfaces.contains(that) || 1.138 + that == OBJECT; 1.139 + } 1.140 + 1.141 + @Override 1.142 + public String asString() { 1.143 + return typeStr; 1.144 + } 1.145 + 1.146 + @Override 1.147 + public boolean isClass() { 1.148 + return true; 1.149 + } 1.150 + 1.151 + @Override 1.152 + public boolean isInterface() { 1.153 + return false; 1.154 + } 1.155 + } 1.156 + 1.157 + enum ModifierKind { 1.158 + NONE(""), 1.159 + FINAL("final"); 1.160 + 1.161 + String modStr; 1.162 + 1.163 + ModifierKind(String modStr) { 1.164 + this.modStr = modStr; 1.165 + } 1.166 + } 1.167 + 1.168 + enum CastKind { 1.169 + CLASS("(#C)", 0), 1.170 + INTERFACE("(#I0)", 1), 1.171 + INTERSECTION2("(#C & #I0)", 1), 1.172 + INTERSECTION3("(#C & #I0 & #I1)", 2); 1.173 + //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3); 1.174 + 1.175 + String castTemplate; 1.176 + int interfaceBounds; 1.177 + 1.178 + CastKind(String castTemplate, int interfaceBounds) { 1.179 + this.castTemplate = castTemplate; 1.180 + this.interfaceBounds = interfaceBounds; 1.181 + } 1.182 + } 1.183 + 1.184 + static class CastInfo { 1.185 + CastKind kind; 1.186 + Type[] types; 1.187 + 1.188 + CastInfo(CastKind kind, Type... types) { 1.189 + this.kind = kind; 1.190 + this.types = types; 1.191 + } 1.192 + 1.193 + String getCast() { 1.194 + String temp = kind.castTemplate.replaceAll("#C", 1.195 + types[0].asString()); 1.196 + for (int i = 0; i < kind.interfaceBounds ; i++) { 1.197 + temp = temp.replace(String.format("#I%d", i), 1.198 + types[i + 1].asString()); 1.199 + } 1.200 + return temp; 1.201 + } 1.202 + 1.203 + boolean hasDuplicateTypes() { 1.204 + for (int i = 0 ; i < types.length ; i++) { 1.205 + for (int j = 0 ; j < types.length ; j++) { 1.206 + if (i != j && types[i] == types[j]) { 1.207 + return true; 1.208 + } 1.209 + } 1.210 + } 1.211 + return false; 1.212 + } 1.213 + 1.214 + boolean compatibleWith(ModifierKind mod, CastInfo that) { 1.215 + for (Type t1 : types) { 1.216 + for (Type t2 : that.types) { 1.217 + boolean compat = 1.218 + t1.subtypeOf(t2) || 1.219 + t2.subtypeOf(t1) || 1.220 + (t1.isInterface() && t2.isInterface()) || //side-cast (1) 1.221 + (mod == ModifierKind.NONE && 1.222 + (t1.isInterface() != t2.isInterface())); //side-cast (2) 1.223 + if (!compat) return false; 1.224 + } 1.225 + } 1.226 + return true; 1.227 + } 1.228 + } 1.229 + 1.230 + public static void main(String... args) throws Exception { 1.231 + for (ModifierKind mod : ModifierKind.values()) { 1.232 + for (CastInfo cast1 : allCastInfo()) { 1.233 + for (CastInfo cast2 : allCastInfo()) { 1.234 + pool.execute( 1.235 + new IntersectionTypeCastTest(mod, cast1, cast2)); 1.236 + } 1.237 + } 1.238 + } 1.239 + checkAfterExec(); 1.240 + } 1.241 + 1.242 + static List<CastInfo> allCastInfo() { 1.243 + ListBuffer<CastInfo> buf = new ListBuffer<>(); 1.244 + for (CastKind kind : CastKind.values()) { 1.245 + for (ClassKind clazz : ClassKind.values()) { 1.246 + if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) { 1.247 + continue; 1.248 + } else if (kind.interfaceBounds == 0) { 1.249 + buf.append(new CastInfo(kind, clazz)); 1.250 + continue; 1.251 + } else { 1.252 + for (InterfaceKind intf1 : InterfaceKind.values()) { 1.253 + if (kind.interfaceBounds == 1) { 1.254 + buf.append(new CastInfo(kind, clazz, intf1)); 1.255 + continue; 1.256 + } else { 1.257 + for (InterfaceKind intf2 : InterfaceKind.values()) { 1.258 + if (kind.interfaceBounds == 2) { 1.259 + buf.append( 1.260 + new CastInfo(kind, clazz, intf1, intf2)); 1.261 + continue; 1.262 + } else { 1.263 + for (InterfaceKind intf3 : InterfaceKind.values()) { 1.264 + buf.append( 1.265 + new CastInfo(kind, clazz, intf1, 1.266 + intf2, intf3)); 1.267 + continue; 1.268 + } 1.269 + } 1.270 + } 1.271 + } 1.272 + } 1.273 + } 1.274 + } 1.275 + } 1.276 + return buf.toList(); 1.277 + } 1.278 + 1.279 + ModifierKind mod; 1.280 + CastInfo cast1, cast2; 1.281 + JavaSource source; 1.282 + DiagnosticChecker diagChecker; 1.283 + 1.284 + IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) { 1.285 + this.mod = mod; 1.286 + this.cast1 = cast1; 1.287 + this.cast2 = cast2; 1.288 + this.source = new JavaSource(); 1.289 + this.diagChecker = new DiagnosticChecker(); 1.290 + } 1.291 + 1.292 + @Override 1.293 + public void run() { 1.294 + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 1.295 + 1.296 + JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, 1.297 + null, null, Arrays.asList(source)); 1.298 + try { 1.299 + ct.analyze(); 1.300 + } catch (Throwable ex) { 1.301 + throw new AssertionError("Error thrown when compiling the following code:\n" + 1.302 + source.getCharContent(true)); 1.303 + } 1.304 + check(); 1.305 + } 1.306 + 1.307 + class JavaSource extends SimpleJavaFileObject { 1.308 + 1.309 + String bodyTemplate = "class Test {\n" + 1.310 + " void test() {\n" + 1.311 + " Object o = #C1#C2null;\n" + 1.312 + " } }"; 1.313 + 1.314 + String source = ""; 1.315 + 1.316 + public JavaSource() { 1.317 + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 1.318 + for (ClassKind ck : ClassKind.values()) { 1.319 + source += ck.getDecl(mod); 1.320 + } 1.321 + for (InterfaceKind ik : InterfaceKind.values()) { 1.322 + source += ik.declStr; 1.323 + } 1.324 + source += bodyTemplate.replaceAll("#C1", cast1.getCast()). 1.325 + replaceAll("#C2", cast2.getCast()); 1.326 + } 1.327 + 1.328 + @Override 1.329 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 1.330 + return source; 1.331 + } 1.332 + } 1.333 + 1.334 + void check() { 1.335 + checkCount.incrementAndGet(); 1.336 + 1.337 + boolean errorExpected = cast1.hasDuplicateTypes() || 1.338 + cast2.hasDuplicateTypes(); 1.339 + 1.340 + errorExpected |= !cast2.compatibleWith(mod, cast1); 1.341 + 1.342 + if (errorExpected != diagChecker.errorFound) { 1.343 + throw new Error("invalid diagnostics for source:\n" + 1.344 + source.getCharContent(true) + 1.345 + "\nFound error: " + diagChecker.errorFound + 1.346 + "\nExpected error: " + errorExpected); 1.347 + } 1.348 + } 1.349 + 1.350 + static class DiagnosticChecker 1.351 + implements javax.tools.DiagnosticListener<JavaFileObject> { 1.352 + 1.353 + boolean errorFound; 1.354 + 1.355 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 1.356 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 1.357 + errorFound = true; 1.358 + } 1.359 + } 1.360 + } 1.361 + 1.362 +}