test/tools/javac/cast/intersection/IntersectionTypeCastTest.java

Mon, 21 Jan 2013 20:14:39 +0000

author
mcimadamore
date
Mon, 21 Jan 2013 20:14:39 +0000
changeset 1511
c7c41a044e7c
parent 1482
954541f13717
child 1520
5c956be64b9e
permissions
-rw-r--r--

8006566: Remove transient lambda-related guards from JavacParser
Summary: Remove transitional internal flag for allowing intersection types in cast
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2012, 2013, 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  */
    24 /*
    25  * @test
    26  * @bug 8002099
    27  * @summary Add support for intersection types in cast expression
    28  * @library ../../lib
    29  * @build JavacTestingAbstractThreadedTest
    30  * @run main/timeout=360 IntersectionTypeCastTest
    31  */
    33 import java.net.URI;
    34 import java.util.Arrays;
    35 import javax.tools.Diagnostic;
    36 import javax.tools.JavaCompiler;
    37 import javax.tools.JavaFileObject;
    38 import javax.tools.SimpleJavaFileObject;
    39 import javax.tools.ToolProvider;
    41 import com.sun.source.util.JavacTask;
    42 import com.sun.tools.javac.util.List;
    43 import com.sun.tools.javac.util.ListBuffer;
    45 public class IntersectionTypeCastTest
    46     extends JavacTestingAbstractThreadedTest
    47     implements Runnable {
    49     interface Type {
    50         boolean subtypeOf(Type that);
    51         String asString();
    52         boolean isClass();
    53         boolean isInterface();
    54     }
    56     enum InterfaceKind implements Type {
    57         A("interface A { }\n", "A", null),
    58         B("interface B { }\n", "B", null),
    59         C("interface C extends A { }\n", "C", A);
    61         String declStr;
    62         String typeStr;
    63         InterfaceKind superInterface;
    65         InterfaceKind(String declStr, String typeStr,
    66                 InterfaceKind superInterface) {
    67             this.declStr = declStr;
    68             this.typeStr = typeStr;
    69             this.superInterface = superInterface;
    70         }
    72         @Override
    73         public boolean subtypeOf(Type that) {
    74             return this == that || superInterface == that ||
    75                    that == ClassKind.OBJECT;
    76         }
    78         @Override
    79         public String asString() {
    80             return typeStr;
    81         }
    83         @Override
    84         public boolean isClass() {
    85             return false;
    86         }
    88         @Override
    89         public boolean isInterface() {
    90             return true;
    91         }
    92     }
    94     enum ClassKind implements Type {
    95         OBJECT(null, "Object"),
    96         CA("#M class CA implements A { }\n", "CA",
    97            InterfaceKind.A),
    98         CB("#M class CB implements B { }\n", "CB",
    99            InterfaceKind.B),
   100         CAB("#M class CAB implements A, B { }\n", "CAB",
   101             InterfaceKind.A, InterfaceKind.B),
   102         CC("#M class CC implements C { }\n", "CC",
   103            InterfaceKind.C, InterfaceKind.A),
   104         CCA("#M class CCA implements C, A { }\n", "CCA",
   105             InterfaceKind.C, InterfaceKind.A),
   106         CCB("#M class CCB implements C, B { }\n", "CCB",
   107             InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
   108         CCAB("#M class CCAB implements C, A, B { }\n", "CCAB",
   109              InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
   111         String declTemplate;
   112         String typeStr;
   113         List<InterfaceKind> superInterfaces;
   115         ClassKind(String declTemplate, String typeStr,
   116                 InterfaceKind... superInterfaces) {
   117             this.declTemplate = declTemplate;
   118             this.typeStr = typeStr;
   119             this.superInterfaces = List.from(superInterfaces);
   120         }
   122         String getDecl(ModifierKind mod) {
   123             return declTemplate != null ?
   124                     declTemplate.replaceAll("#M", mod.modStr) :
   125                     "";
   126         }
   128         @Override
   129         public boolean subtypeOf(Type that) {
   130             return this == that || superInterfaces.contains(that) ||
   131                     that == OBJECT;
   132         }
   134         @Override
   135         public String asString() {
   136             return typeStr;
   137         }
   139         @Override
   140         public boolean isClass() {
   141             return true;
   142         }
   144         @Override
   145         public boolean isInterface() {
   146             return false;
   147         }
   148     }
   150     enum ModifierKind {
   151         NONE(""),
   152         FINAL("final");
   154         String modStr;
   156         ModifierKind(String modStr) {
   157             this.modStr = modStr;
   158         }
   159     }
   161     enum CastKind {
   162         CLASS("(#C)", 0),
   163         INTERFACE("(#I0)", 1),
   164         INTERSECTION2("(#C & #I0)", 1),
   165         INTERSECTION3("(#C & #I0 & #I1)", 2);
   166         //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3);
   168         String castTemplate;
   169         int interfaceBounds;
   171         CastKind(String castTemplate, int interfaceBounds) {
   172             this.castTemplate = castTemplate;
   173             this.interfaceBounds = interfaceBounds;
   174         }
   175     }
   177     static class CastInfo {
   178         CastKind kind;
   179         Type[] types;
   181         CastInfo(CastKind kind, Type... types) {
   182             this.kind = kind;
   183             this.types = types;
   184         }
   186         String getCast() {
   187             String temp = kind.castTemplate.replaceAll("#C",
   188                     types[0].asString());
   189             for (int i = 0; i < kind.interfaceBounds ; i++) {
   190                 temp = temp.replace(String.format("#I%d", i),
   191                                     types[i + 1].asString());
   192             }
   193             return temp;
   194         }
   196         boolean hasDuplicateTypes() {
   197             for (int i = 0 ; i < types.length ; i++) {
   198                 for (int j = 0 ; j < types.length ; j++) {
   199                     if (i != j && types[i] == types[j]) {
   200                         return true;
   201                     }
   202                 }
   203             }
   204             return false;
   205         }
   207         boolean compatibleWith(ModifierKind mod, CastInfo that) {
   208             for (Type t1 : types) {
   209                 for (Type t2 : that.types) {
   210                     boolean compat =
   211                             t1.subtypeOf(t2) ||
   212                             t2.subtypeOf(t1) ||
   213                             (t1.isInterface() && t2.isInterface()) || //side-cast (1)
   214                             (mod == ModifierKind.NONE &&
   215                             (t1.isInterface() != t2.isInterface())); //side-cast (2)
   216                     if (!compat) return false;
   217                 }
   218             }
   219             return true;
   220         }
   221     }
   223     public static void main(String... args) throws Exception {
   224         for (ModifierKind mod : ModifierKind.values()) {
   225             for (CastInfo cast1 : allCastInfo()) {
   226                 for (CastInfo cast2 : allCastInfo()) {
   227                     pool.execute(
   228                         new IntersectionTypeCastTest(mod, cast1, cast2));
   229                 }
   230             }
   231         }
   232         checkAfterExec();
   233     }
   235     static List<CastInfo> allCastInfo() {
   236         ListBuffer<CastInfo> buf = ListBuffer.lb();
   237         for (CastKind kind : CastKind.values()) {
   238             for (ClassKind clazz : ClassKind.values()) {
   239                 if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) {
   240                     continue;
   241                 } else if (kind.interfaceBounds == 0) {
   242                     buf.append(new CastInfo(kind, clazz));
   243                     continue;
   244                 } else {
   245                     for (InterfaceKind intf1 : InterfaceKind.values()) {
   246                         if (kind.interfaceBounds == 1) {
   247                             buf.append(new CastInfo(kind, clazz, intf1));
   248                             continue;
   249                         } else {
   250                             for (InterfaceKind intf2 : InterfaceKind.values()) {
   251                                 if (kind.interfaceBounds == 2) {
   252                                     buf.append(
   253                                             new CastInfo(kind, clazz, intf1, intf2));
   254                                     continue;
   255                                 } else {
   256                                     for (InterfaceKind intf3 : InterfaceKind.values()) {
   257                                         buf.append(
   258                                                 new CastInfo(kind, clazz, intf1,
   259                                                              intf2, intf3));
   260                                         continue;
   261                                     }
   262                                 }
   263                             }
   264                         }
   265                     }
   266                 }
   267             }
   268         }
   269         return buf.toList();
   270     }
   272     ModifierKind mod;
   273     CastInfo cast1, cast2;
   274     JavaSource source;
   275     DiagnosticChecker diagChecker;
   277     IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) {
   278         this.mod = mod;
   279         this.cast1 = cast1;
   280         this.cast2 = cast2;
   281         this.source = new JavaSource();
   282         this.diagChecker = new DiagnosticChecker();
   283     }
   285     @Override
   286     public void run() {
   287         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
   289         JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
   290                 null, null, Arrays.asList(source));
   291         try {
   292             ct.analyze();
   293         } catch (Throwable ex) {
   294             throw new AssertionError("Error thrown when compiling the following code:\n" +
   295                     source.getCharContent(true));
   296         }
   297         check();
   298     }
   300     class JavaSource extends SimpleJavaFileObject {
   302         String bodyTemplate = "class Test {\n" +
   303                               "   void test() {\n" +
   304                               "      Object o = #C1#C2null;\n" +
   305                               "   } }";
   307         String source = "";
   309         public JavaSource() {
   310             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   311             for (ClassKind ck : ClassKind.values()) {
   312                 source += ck.getDecl(mod);
   313             }
   314             for (InterfaceKind ik : InterfaceKind.values()) {
   315                 source += ik.declStr;
   316             }
   317             source += bodyTemplate.replaceAll("#C1", cast1.getCast()).
   318                     replaceAll("#C2", cast2.getCast());
   319         }
   321         @Override
   322         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   323             return source;
   324         }
   325     }
   327     void check() {
   328         checkCount.incrementAndGet();
   330         boolean errorExpected = cast1.hasDuplicateTypes() ||
   331                 cast2.hasDuplicateTypes();
   333         errorExpected |= !cast2.compatibleWith(mod, cast1);
   335         if (errorExpected != diagChecker.errorFound) {
   336             throw new Error("invalid diagnostics for source:\n" +
   337                 source.getCharContent(true) +
   338                 "\nFound error: " + diagChecker.errorFound +
   339                 "\nExpected error: " + errorExpected);
   340         }
   341     }
   343     static class DiagnosticChecker
   344         implements javax.tools.DiagnosticListener<JavaFileObject> {
   346         boolean errorFound;
   348         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   349             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   350                 errorFound = true;
   351             }
   352         }
   353     }
   355 }

mercurial