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