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 8002099
27 * @summary Add support for intersection types in cast expression
28 * @modules jdk.compiler
29 */
30
31import com.sun.source.util.JavacTask;
32import java.net.URI;
33import java.util.Arrays;
34import javax.tools.Diagnostic;
35import javax.tools.JavaCompiler;
36import javax.tools.JavaFileObject;
37import javax.tools.SimpleJavaFileObject;
38import javax.tools.StandardJavaFileManager;
39import javax.tools.ToolProvider;
40
41public class IntersectionTypeParserTest {
42
43    static int checkCount = 0;
44
45    enum TypeKind {
46        SIMPLE("A"),
47        GENERIC("A<X>"),
48        WILDCARD("A<? super X, ? extends Y>");
49
50        String typeStr;
51
52        TypeKind(String typeStr) {
53            this.typeStr = typeStr;
54        }
55    }
56
57    enum ArrayKind {
58        NONE(""),
59        SINGLE("[]"),
60        DOUBLE("[][]");
61
62        String arrStr;
63
64        ArrayKind(String arrStr) {
65            this.arrStr = arrStr;
66        }
67    }
68
69    static class Type {
70        TypeKind tk;
71        ArrayKind ak;
72
73        Type(TypeKind tk, ArrayKind ak) {
74            this.tk = tk;
75            this.ak = ak;
76        }
77
78        String asString() {
79            return tk.typeStr + ak.arrStr;
80        }
81    }
82
83    enum CastKind {
84        ONE("(#T0)", 1),
85        TWO("(#T0 & T1)", 2),
86        THREE("(#T0 & #T1 & #T2)", 3);
87
88        String castTemplate;
89        int nBounds;
90
91        CastKind(String castTemplate, int nBounds) {
92            this.castTemplate = castTemplate;
93            this.nBounds = nBounds;
94        }
95
96        String asString(Type... types) {
97            String res = castTemplate;
98            for (int i = 0; i < nBounds ; i++) {
99                res = res.replaceAll(String.format("#T%d", i), types[i].asString());
100            }
101            return res;
102        }
103    }
104
105    public static void main(String... args) throws Exception {
106        //create default shared JavaCompiler - reused across multiple compilations
107        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
108        try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
109
110            for (CastKind ck : CastKind.values()) {
111                for (TypeKind t1 : TypeKind.values()) {
112                    for (ArrayKind ak1 : ArrayKind.values()) {
113                        Type typ1 = new Type(t1, ak1);
114                        if (ck.nBounds == 1) {
115                            new IntersectionTypeParserTest(ck, typ1).run(comp, fm);
116                            continue;
117                        }
118                        for (TypeKind t2 : TypeKind.values()) {
119                            for (ArrayKind ak2 : ArrayKind.values()) {
120                                Type typ2 = new Type(t2, ak2);
121                                if (ck.nBounds == 2) {
122                                    new IntersectionTypeParserTest(ck, typ1, typ2).run(comp, fm);
123                                    continue;
124                                }
125                                for (TypeKind t3 : TypeKind.values()) {
126                                    for (ArrayKind ak3 : ArrayKind.values()) {
127                                        Type typ3 = new Type(t3, ak3);
128                                        new IntersectionTypeParserTest(ck, typ1, typ2, typ3).run(comp, fm);
129                                    }
130                                }
131                            }
132                        }
133                    }
134                }
135            }
136            System.out.println("Total check executed: " + checkCount);
137        }
138    }
139
140    CastKind ck;
141    Type[] types;
142    JavaSource source;
143    DiagnosticChecker diagChecker;
144
145    IntersectionTypeParserTest(CastKind ck, Type... types) {
146        this.ck = ck;
147        this.types = types;
148        this.source = new JavaSource();
149        this.diagChecker = new DiagnosticChecker();
150    }
151
152    class JavaSource extends SimpleJavaFileObject {
153
154        String bodyTemplate = "class Test {\n" +
155                              "   void test() {\n" +
156                              "      Object o = #Cnull;\n" +
157                              "   } }";
158
159        String source = "";
160
161        public JavaSource() {
162            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
163            source += bodyTemplate.replaceAll("#C", ck.asString(types));
164        }
165
166        @Override
167        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
168            return source;
169        }
170    }
171
172    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
173        checkCount++;
174        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
175                null, null, Arrays.asList(source));
176        ct.parse();
177        if (diagChecker.errorFound) {
178            throw new Error("Unexpected parser error for source:\n" +
179                source.getCharContent(true));
180        }
181    }
182
183    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
184
185        boolean errorFound;
186
187        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
188            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
189                errorFound = true;
190            }
191        }
192    }
193}
194