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