Sat, 13 Apr 2013 12:25:44 +0100
8010659: Javac Crashes while building OpenJFX
Reviewed-by: jjg
Contributed-by: maurizio.cimadamore@oracle.com
1 /*
2 * Copyright (c) 2009, 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 import java.io.BufferedWriter;
25 import java.io.File;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.io.PrintStream;
29 import java.io.PrintWriter;
30 import java.lang.annotation.*;
31 import java.lang.reflect.*;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
38 import com.sun.tools.classfile.ClassFile;
39 import com.sun.tools.classfile.TypeAnnotation;
40 import com.sun.tools.classfile.TypeAnnotation.TargetType;
42 public class Driver {
44 private static final PrintStream out = System.out;
46 public static void main(String[] args) throws Exception {
47 if (args.length == 0 || args.length > 1)
48 throw new IllegalArgumentException("Usage: java Driver <test-name>");
49 String name = args[0];
50 Class<?> clazz = Class.forName(name);
51 new Driver().runDriver(clazz.newInstance());
52 }
54 protected void runDriver(Object object) throws Exception {
55 int passed = 0, failed = 0;
56 Class<?> clazz = object.getClass();
57 out.println("Tests for " + clazz.getName());
59 // Find methods
60 for (Method method : clazz.getMethods()) {
61 Map<String, TypeAnnotation.Position> expected = expectedOf(method);
62 if (expected == null)
63 continue;
64 if (method.getReturnType() != String.class)
65 throw new IllegalArgumentException("Test method needs to return a string: " + method);
66 String testClass = testClassOf(method);
68 try {
69 String compact = (String)method.invoke(object);
70 String fullFile = wrap(compact);
71 ClassFile cf = compileAndReturn(fullFile, testClass);
72 List<TypeAnnotation> actual = ReferenceInfoUtil.extendedAnnotationsOf(cf);
73 ReferenceInfoUtil.compare(expected, actual, cf);
74 out.println("PASSED: " + method.getName());
75 ++passed;
76 } catch (Throwable e) {
77 out.println("FAILED: " + method.getName());
78 out.println(" " + e.toString());
79 ++failed;
80 }
81 }
83 out.println();
84 int total = passed + failed;
85 out.println(total + " total tests: " + passed + " PASSED, " + failed + " FAILED");
87 out.flush();
89 if (failed != 0)
90 throw new RuntimeException(failed + " tests failed");
91 }
93 private Map<String, TypeAnnotation.Position> expectedOf(Method m) {
94 TADescription ta = m.getAnnotation(TADescription.class);
95 TADescriptions tas = m.getAnnotation(TADescriptions.class);
97 if (ta == null && tas == null)
98 return null;
100 Map<String, TypeAnnotation.Position> result =
101 new HashMap<String, TypeAnnotation.Position>();
103 if (ta != null)
104 result.putAll(expectedOf(ta));
106 if (tas != null) {
107 for (TADescription a : tas.value()) {
108 result.putAll(expectedOf(a));
109 }
110 }
112 return result;
113 }
115 private Map<String, TypeAnnotation.Position> expectedOf(TADescription d) {
116 String annoName = d.annotation();
118 TypeAnnotation.Position p = new TypeAnnotation.Position();
119 p.type = d.type();
120 if (d.offset() != NOT_SET)
121 p.offset = d.offset();
122 if (d.lvarOffset().length != 0)
123 p.lvarOffset = d.lvarOffset();
124 if (d.lvarLength().length != 0)
125 p.lvarLength = d.lvarLength();
126 if (d.lvarIndex().length != 0)
127 p.lvarIndex = d.lvarIndex();
128 if (d.boundIndex() != NOT_SET)
129 p.bound_index = d.boundIndex();
130 if (d.paramIndex() != NOT_SET)
131 p.parameter_index = d.paramIndex();
132 if (d.typeIndex() != NOT_SET)
133 p.type_index = d.typeIndex();
134 if (d.exceptionIndex() != NOT_SET)
135 p.exception_index = d.exceptionIndex();
136 if (d.genericLocation().length != 0) {
137 p.location = TypeAnnotation.Position.getTypePathFromBinary(wrapIntArray(d.genericLocation()));
138 }
140 return Collections.singletonMap(annoName, p);
141 }
143 private List<Integer> wrapIntArray(int[] ints) {
144 List<Integer> list = new ArrayList<Integer>(ints.length);
145 for (int i : ints)
146 list.add(i);
147 return list;
148 }
150 private String testClassOf(Method m) {
151 TestClass tc = m.getAnnotation(TestClass.class);
152 if (tc != null) {
153 return tc.value();
154 } else {
155 return "Test";
156 }
157 }
159 private ClassFile compileAndReturn(String fullFile, String testClass) throws Exception {
160 File source = writeTestFile(fullFile);
161 File clazzFile = compileTestFile(source, testClass);
162 return ClassFile.read(clazzFile);
163 }
165 protected File writeTestFile(String fullFile) throws IOException {
166 File f = new File("Test.java");
167 PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
168 out.println(fullFile);
169 out.close();
170 return f;
171 }
173 protected File compileTestFile(File f, String testClass) {
174 int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.8", "-g", f.getPath() });
175 if (rc != 0)
176 throw new Error("compilation failed. rc=" + rc);
177 String path;
178 if (f.getParent() != null) {
179 path = f.getParent();
180 } else {
181 path = "";
182 }
184 return new File(path + testClass + ".class");
185 }
187 private String wrap(String compact) {
188 StringBuilder sb = new StringBuilder();
190 // Automatically import java.util
191 sb.append("\nimport java.util.*;");
192 sb.append("\nimport java.lang.annotation.*;");
194 sb.append("\n\n");
195 boolean isSnippet = !(compact.startsWith("class")
196 || compact.contains(" class"))
197 && !compact.contains("interface")
198 && !compact.contains("enum");
199 if (isSnippet)
200 sb.append("class Test {\n");
202 sb.append(compact);
203 sb.append("\n");
205 if (isSnippet)
206 sb.append("}\n\n");
208 if (isSnippet) {
209 // Have a few common nested types for testing
210 sb.append("class Outer { class Inner {} }");
211 sb.append("class SOuter { static class SInner {} }");
212 sb.append("class GOuter<X, Y> { class GInner<X, Y> {} }");
213 }
215 // create A ... F annotation declarations
216 sb.append("\n@interface A {}");
217 sb.append("\n@interface B {}");
218 sb.append("\n@interface C {}");
219 sb.append("\n@interface D {}");
220 sb.append("\n@interface E {}");
221 sb.append("\n@interface F {}");
223 // create TA ... TF proper type annotations
224 sb.append("\n");
225 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TA {}");
226 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TB {}");
227 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TC {}");
228 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TD {}");
229 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TE {}");
230 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TF {}");
231 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TG {}");
232 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TH {}");
233 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TI {}");
234 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TJ {}");
235 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TK {}");
236 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TL {}");
237 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface TM {}");
239 // create RTA, RTAs, RTB, RTBs for repeating type annotations
240 sb.append("\n");
241 sb.append("\n@Repeatable(RTAs.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTA {}");
242 sb.append("\n@Repeatable(RTBs.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTB {}");
244 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTAs { RTA[] value(); }");
245 sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTBs { RTB[] value(); }");
247 sb.append("\n@Target(value={ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.CONSTRUCTOR,ElementType.LOCAL_VARIABLE})");
248 sb.append("\n@interface Decl {}");
250 return sb.toString();
251 }
253 public static final int NOT_SET = -888;
255 }
257 @Retention(RetentionPolicy.RUNTIME)
258 @Target(ElementType.METHOD)
259 @interface TADescription {
260 String annotation();
262 TargetType type();
263 int offset() default Driver.NOT_SET;
264 int[] lvarOffset() default { };
265 int[] lvarLength() default { };
266 int[] lvarIndex() default { };
267 int boundIndex() default Driver.NOT_SET;
268 int paramIndex() default Driver.NOT_SET;
269 int typeIndex() default Driver.NOT_SET;
270 int exceptionIndex() default Driver.NOT_SET;
272 int[] genericLocation() default {};
273 }
275 @Retention(RetentionPolicy.RUNTIME)
276 @Target(ElementType.METHOD)
277 @interface TADescriptions {
278 TADescription[] value() default {};
279 }
281 /**
282 * The name of the class that should be analyzed.
283 * Should only need to be provided when analyzing inner classes.
284 */
285 @Retention(RetentionPolicy.RUNTIME)
286 @Target(ElementType.METHOD)
287 @interface TestClass {
288 String value() default "Test";
289 }