Tue, 14 May 2013 15:04:06 -0700
8013852: update reference impl for type-annotations
Reviewed-by: jjg
Contributed-by: wdietl@gmail.com, steve.sides@oracle.com, joel.franck@oracle.com, alex.buckley@oracle.com
1 /*
2 * Copyright (c) 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 8005085 8005877 8004829 8005681 8006734 8006775 8006507
27 * @summary Combinations of Target ElementTypes on (repeated)type annotations.
28 */
30 import com.sun.tools.classfile.*;
31 import java.io.File;
33 public class CombinationsTargetTest2 extends ClassfileTestHelper {
35 // Test count helps identify test case in event of failure.
36 int testcount = 0;
38 // Base test case template descriptions
39 enum srce {
40 src1("(repeating) type annotations on on field in method body",true),
41 src2("(repeating) type annotations on type parameters, bounds and type arguments", true),
42 src3("(repeating) type annotations on type parameters of class, method return value in method", true),
43 src4("(repeating) type annotations on field in anonymous class", false),
44 src5("(repeating) type annotations on field in anonymous class", false);
46 String description;
47 Boolean local;
49 srce(String desc, Boolean b) {
50 this.description = this + ": " +desc;
51 this.local = b;
52 }
53 }
56 String[] ETypes={"TYPE", "FIELD", "METHOD", "PARAMETER", "CONSTRUCTOR",
57 "LOCAL_VARIABLE", "ANNOTATION_TYPE", "PACKAGE"};
59 // local class tests will have an inner class.
60 Boolean hasInnerClass=false;
61 String innerClassname="";
63 public static void main(String[] args) throws Exception {
64 new CombinationsTargetTest2().run();
65 }
67 void run() throws Exception {
68 // Determines which repeat and order in source(ABMix).
69 Boolean As= false, BDs=true, ABMix=false;
70 int testrun=0;
71 Boolean [][] bRepeat = new Boolean[][]{{false,false,false},//no repeats
72 {true,false,false}, //repeat @A
73 {false,true,false}, //repeat @B
74 {true,true,false}, //repeat both
75 {false,false,true} //repeat mix
76 };
78 for(Boolean[] bCombo : bRepeat) {
79 As=bCombo[0]; BDs=bCombo[1]; ABMix=bCombo[2];
80 for(String et : ETypes) {
81 switch(et) {
82 case "METHOD":
83 test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src1);
84 test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src1);
85 test( 2, 0, 2, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src5);
86 test( 0, 2, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src5);
87 break;
88 case "FIELD":
89 test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src1);
90 test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src2);
91 test( 6, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src3);
92 test( 2, 0, 2, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src4);
93 test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src1);
94 test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src2);
95 test( 0, 6, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src3);
96 test( 0, 2, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src4);
97 break;
98 default:/*TYPE,PARAMETER,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE*/
99 test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src4);
100 test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src5);
101 break;
102 }
103 }
104 }
105 }
107 public void test(int tinv, int tvis, int inv, int vis, Boolean Arepeats,
108 Boolean BDrepeats, Boolean ABmix, String rtn, String et2,
109 Integer N, srce source) throws Exception {
110 ++testcount;
111 expected_tvisibles = tvis;
112 expected_tinvisibles = tinv;
113 expected_visibles = vis;
114 expected_invisibles = inv;
115 File testFile = null;
116 String tname="Test" + N.toString();
117 hasInnerClass=false;
118 String testDef = "Test " + testcount + " parameters: tinv=" + tinv +
119 ", tvis=" + tvis + ", inv=" + inv + ", vis=" + vis +
120 ", Arepeats=" + Arepeats + ", BDrepeats=" + BDrepeats +
121 ", ABmix=" + ABmix + ", retention: " + rtn + ", anno2: " +
122 et2 + ", src=" + source + "\n " + source.description;
124 if(
125 // 8005681 - src1,2,3 - skip cases with repeated annotations on new, array, cast.
126 (( source.equals(srce.src1) || source.equals(srce.src2) ||
127 source.equals(srce.src3)) && (ABmix || (Arepeats && BDrepeats)))
128 // 8008928 - src4,5 - this change cause crash with t-a on anon class)
129 || (source.equals(srce.src4) || source.equals(srce.src5))
130 ) {
131 System.out.println(testDef +
132 "\n 8005681-skip repeated annotations on new,array,cast");
133 return;
134 }
136 println(testDef);
137 // Create test source and File.
138 String sourceString = sourceString(tname, rtn, et2, Arepeats,
139 BDrepeats, ABmix, source);
140 testFile = writeTestFile(tname+".java", sourceString);
141 // Compile test source and read classfile.
142 File classFile = null;
143 try {
144 classFile = compile(testFile);
145 } catch (Error err) {
146 System.err.println("Failed compile. Source:\n" + sourceString);
147 throw err;
148 }
149 //if sourcString() set hasInnerClass it also set innerClassname.
150 if(hasInnerClass) {
151 StringBuffer sb = new StringBuffer(classFile.getAbsolutePath());
152 classFile=new File(sb.insert(sb.lastIndexOf(".class"),innerClassname).toString());
153 println("classfile: " + classFile.getAbsolutePath());
154 }
155 ClassFile cf = ClassFile.read(classFile);
157 //Test class,fields and method counts.
158 test(cf);
160 for (Field f : cf.fields) {
161 if(source.local)
162 test(cf, f, true);
163 else
164 test(cf,f);
165 }
166 for (Method m: cf.methods) {
167 if(source.local)
168 test(cf, m, true);
169 else
170 test(cf, m);
171 }
172 countAnnotations();
173 if (errors > 0) {
174 System.err.println( testDef );
175 System.err.println( "Source:\n" + sourceString );
176 throw new Exception( errors + " errors found" );
177 }
178 println("Pass");
179 }
181 //
182 // Source for test cases
183 //
184 String sourceString(String testname, String retentn, String annot2,
185 Boolean Arepeats, Boolean BDrepeats, Boolean ABmix,
186 srce src) {
188 String As = "@A", Bs = "@B", Ds = "@D";
189 if(Arepeats) As = "@A @A";
190 if(BDrepeats) {
191 Bs = "@B @B";
192 Ds = "@D @D";
193 }
194 if(ABmix) { As = "@A @B"; Bs = "@A @B"; Ds = "@D @D"; }
196 // Source to check for TYPE_USE and TYPE_PARAMETER annotations.
197 // Source base (annotations) is same for all test cases.
198 String source = new String();
199 String imports = new String("import java.lang.annotation.*; \n" +
200 "import static java.lang.annotation.RetentionPolicy.*; \n" +
201 "import static java.lang.annotation.ElementType.*; \n" +
202 "import java.util.List; \n" +
203 "import java.util.HashMap; \n" +
204 "import java.util.Map; \n\n");
206 String sourceBase = new String("@Retention("+retentn+")\n" +
207 "@Target({TYPE_USE,_OTHER_})\n" +
208 "@Repeatable( AC.class )\n" +
209 "@interface A { }\n\n" +
211 "@Retention("+retentn+")\n" +
212 "@Target({TYPE_USE,_OTHER_})\n" +
213 "@interface AC { A[] value(); }\n\n" +
215 "@Retention("+retentn+")\n" +
216 "@Target({TYPE_USE,_OTHER_})\n" +
217 "@Repeatable( BC.class )\n" +
218 "@interface B { }\n\n" +
220 "@Retention("+retentn+")\n" +
221 "@Target({TYPE_USE,_OTHER_})\n" +
222 "@interface BC { B[] value(); } \n\n" +
224 "@Retention("+retentn+")\n" +
225 "@Target({TYPE_USE,TYPE_PARAMETER,_OTHER_})\n" +
226 "@Repeatable(DC.class)\n" +
227 "@interface D { }\n\n" +
229 "@Retention("+retentn+")\n" +
230 "@Target({TYPE_USE,TYPE_PARAMETER,_OTHER_})\n" +
231 "@interface DC { D[] value(); }\n\n");
233 // Test case sources with sample generated source
234 switch(src) {
235 case src1: // (repeating) type annotations on field in method body
236 /*
237 * class Test1 {
238 * Test1(){}
239 * // type usage in method body
240 * String test(Test1 this, String param, String ... vararg) {
241 * @A @B
242 * Object o = new @A @B String @A @B [3];
243 * return (@A @B String) null;
244 * }}
245 */
246 source = new String(
247 "// " + src.description + "\n" +
248 "class " + testname + " {\n" +
249 "" + testname +"(){} \n" +
250 "// type usage in method body \n" +
251 "String test("+testname+" this, " +
252 "String param, String ... vararg) { \n" +
253 " _As_ _Bs_\n Object o = new _As_ _Bs_ String _As_ _Bs_ [3]; \n" +
254 " return (_As_ _Bs_ String) null; \n" +
255 "} \n" +
256 "} \n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
257 "\n\n";
258 break;
259 case src2: // (repeating) annotations on type parameters, bounds and type arguments in new statement.
260 /*
261 * class Test2<T extends Object> {
262 * Map<List<String>, Integer> map =
263 * new HashMap<@A @B List<@A @B String>, @A @B Integer>();
264 * Map<List<String>, Integer> map2 = new @A @B HashMap<>();
265 * String test(Test2<T> this) { return null;}
266 * <T> String genericMethod(T t) { return null; }
267 * }
268 */
269 source = new String( source +
270 "// " + src.description + "\n" +
271 "class " + testname + "<T extends Object> {\n" +
272 " Map<List<String>, Integer> map =\n" +
273 " new HashMap<_As_ _Bs_ List<_As_ _Bs_ String>, _As_ _Bs_ Integer>();\n" +
274 " Map<List<String>, Integer> map2 = new _As_ _Bs_ HashMap<>();\n" +
275 " String test(" + testname + "<T> this) { return null;}\n" +
276 " <T> String genericMethod(T t) { return null; }\n" +
277 "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
278 "\n\n";
279 break;
280 case src3: // (repeating)annotations on type parameters of class, method return value in method.
281 /*
282 * class Test3{
283 * <E extends Comparable> Map<List<E>, E > foo(E e) {
284 * class maptest <E> {
285 * Map<List<E>,E> getMap() {
286 * Map<List<E>,E> Em = new HashMap<List<@A @B @D E>,@A @B @D E>();
287 * return Em;
288 * }
289 * }
290 * return new maptest<E>().getMap();
291 * }
292 * Map<List<String>,String> shm = foo(new String("hello"));
293 * }
294 */
295 source = new String( source +
296 "// " + src.description + "\n" +
297 "class "+ testname + "{\n" +
298 " <E extends Comparable> Map<List<E>, E > foo(E e) {\n" +
299 " class maptest <E> {\n" + // inner class $1maptest
300 " Map<List<E>,E> getMap() { \n" +
301 " Map<List<E>,E> Em = new HashMap<List<_As_ _Bs_ _Ds_ E>,_As_ _Bs_ _Ds_ E>();\n" +
302 " return Em;\n" +
303 " }\n" +
304 " }\n" +
305 " return new maptest<E>().getMap();\n" +
306 " }\n" +
307 " Map<List<String>,String> shm = foo(new String(\"hello\"));\n" +
308 "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs).replace("_Ds_",Ds) +
309 "\n\n";
310 hasInnerClass=true;
311 innerClassname="$1maptest";
312 break;
313 case src4: // (repeating)annotations on field in anonymous class
314 /*
315 * class Test95{
316 * void mtest( Test95 t){ }
317 * public void test() {
318 * mtest( new Test95() {
319 * @A @A @B @B String data2 = "test";
320 * });
321 * }
322 * }
323 */
324 source = new String( source +
325 "// " + src.description + "\n" +
326 "class "+ testname + "{\n" +
327 " void mtest( "+ testname + " t){ }\n" +
328 " public void test() {\n" +
329 " mtest( new "+ testname + "() {\n" +
330 " _As_ _Bs_ String data2 = \"test\";\n" +
331 " });\n" +
332 " }\n" +
333 "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
334 "\n\n";
335 hasInnerClass=true;
336 innerClassname="$1";
337 break;
338 case src5: // (repeating)annotations on method in anonymous class
339 /*
340 * class Test120{
341 * void mtest( Test120 t){ }
342 * public void test() {
343 * mtest( new Test120() {
344 * @A @B @A @B String m2(){return null;};
345 * });
346 * }
347 */
348 source = new String( source +
349 "// " + src.description + "\n" +
350 "class "+ testname + "{\n" +
351 " void mtest( "+ testname + " t){ }\n" +
352 " public void test() {\n" +
353 " mtest( new "+ testname + "() {\n" +
354 " _As_ _Bs_ String m2(){return null;};\n" +
355 " });\n" +
356 " }\n" +
357 "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
358 "\n\n";
359 hasInnerClass=true;
360 innerClassname="$1";
361 break;
362 }
363 return imports + source;
364 }
365 }