CombinationsTargetTest3.java revision 2942:08092deced3f
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 8005681 8008769 8010015 27 * @summary Check (repeating)type annotations on lambda usage. 28 * @modules jdk.jdeps/com.sun.tools.classfile 29 * @run main CombinationsTargetTest3 30 */ 31 32import com.sun.tools.classfile.*; 33import java.io.File; 34import java.util.Vector; 35 36public class CombinationsTargetTest3 extends ClassfileTestHelper { 37 38 // Helps identify test case in event of failure. 39 int testcount = 0; 40 41 // Known failure cases due to open bugs. 42 Vector<String> skippedTests = new Vector<>(); 43 void printSkips() { 44 if(!skippedTests.isEmpty()) { 45 println(skippedTests.size() + " tests were skipped:"); 46 for(String t : skippedTests) 47 println(" " + t); 48 } 49 } 50 51 // Test case descriptions and expected annotation counts. 52 enum srce { 53 src1("type annotations on lambda expression as method arg.",4,0), 54 src2("type annotations on new in single line lambda expression",2,0), 55 src3("type annotations in lambda expression code block",4,0), 56 src4("type annotations in code block with recursion,cast",2,0), 57 src5("type annotations in lambda expression code block",4,0), 58 src6("type annotations on type parm in method reference",4,0), 59 src7("type annotations on inner class field of lambda expression",2,2), 60 src8("type annotations in inner class of lambda expression",4,2), 61 src9("type annotations on static method of interface",4,2); 62 63 String description; 64 // Expected annotation counts are same for Vis or Invis, but which one 65 // depends on retention type. 66 Integer[] exp = { 0, 0 }; 67 68 // If class to test is inner class, this may be set in SourceString() 69 String innerClassname = null ; 70 71 // If class to test is not main or inner class; set in sourceString() 72 String altClassName = null; 73 74 srce(String desc, int e1, int e2) { 75 description = this + ": " +desc; 76 exp[0]=e1; 77 exp[1]=e2; 78 } 79 } 80 81 // Check for RuntimeInvisible or RuntimeVisible annotations. 82 String[] RType={"CLASS", "RUNTIME"}; 83 84 // This can be a compile only test. 85 static boolean compileonly=false; 86 87 // Collect failure for end of test report() 88 Vector<String> vFailures = new Vector<>(); 89 90 // pass/fail determined after all tests have run. 91 void report() { 92 if(vFailures.isEmpty()) { 93 printSkips(); 94 println("PASS"); 95 } else { 96 System.err.println("FAILED: There were failures:"); 97 for(String f : vFailures) 98 System.err.println(f); 99 throw new RuntimeException("There were failures. See test log."); 100 } 101 } 102 103 public static void main(String[] args) throws Exception { 104 if(args.length>0 && args[0].compareTo("compileonly")==0) 105 compileonly=true; 106 new CombinationsTargetTest3().run(); 107 } 108 109 void run() throws Exception { 110 // Determines which repeat and order in source(ABMix). 111 Boolean As= false, BDs=true, ABMix=false; 112 int testrun=0; 113 // A repeats and/or B/D repeats, ABMix for order of As and Bs. 114 Boolean [][] bRepeat = new Boolean[][]{{false,false,false}, //no repeats 115 {true,false,false}, //repeat @A 116 {false,true,false}, //repeat @B 117 {true,true,false}, //repeat both 118 {false,false,true} //repeat mix 119 }; 120 // Added ElementType's. All set; not permuted (so far) for this test 121 String et = "TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE"; 122 123 // test loop 124 for(Boolean[] bCombo : bRepeat) { 125 As=bCombo[0]; BDs=bCombo[1]; ABMix=bCombo[2]; 126 for(srce src : srce.values()) 127 for( String rtype : RType ) { 128 switch( rtype ) { 129 case "RUNTIME": 130 test(0,src.exp[0],0,src.exp[1],As, BDs, ABMix, 131 "RUNTIME", et, ++testrun, src); 132 break; 133 case "CLASS": 134 test(src.exp[0],0,src.exp[1],0,As, BDs, ABMix, 135 "CLASS", et, ++testrun, src); 136 break; 137 } 138 } 139 } 140 report(); 141 } 142 143 // Filter out skipped cases, compile, pass class file to test method, 144 // count annotations and asses results. 145 public void test(int tinv, int tvis, int inv, int vis, Boolean Arepeats, 146 Boolean BDrepeats, Boolean ABmix, String rtn, String et2, 147 Integer N, srce source) throws Exception { 148 ++testcount; 149 expected_tvisibles = tvis; 150 expected_tinvisibles = tinv; 151 expected_visibles = vis; 152 expected_invisibles = inv; 153 File testFile = null; 154 String tname="Test" + N.toString(); 155 String testDef = "Test " + testcount + " parameters: tinv=" + tinv + 156 ", tvis=" + tvis + ", inv=" + inv + ", vis=" + vis + 157 ", Arepeats=" + Arepeats + ", BDrepeats=" + BDrepeats + 158 ", ABmix=" + ABmix + ", retention: " + rtn + ", anno2: " + 159 et2 + ", src=" + source; 160 161 // Skip failing cases with bug ID's 162 if ((source.equals(srce.src2) || source.equals(srce.src4) || 163 source.equals(srce.src5)) && 164 (ABmix || (Arepeats && BDrepeats))) { 165 skippedTests.add(testDef + 166 "\n--8005681 repeated type-annotations on new/cast/array in" + 167 " inner class in lambda expression."); 168 return; 169 }//8008769 Repeated type-annotations on type parm of local variable 170 else if (source.equals(srce.src6) && 171 (ABmix || (Arepeats && BDrepeats))) { 172 skippedTests.add(testDef + "\n--8008769 Repeated " + 173 "type-annotations on type parm of local variable"); 174 return; 175 } 176 177 println(testDef); 178 // Create test source and File. 179 String sourceString = sourceString(tname, rtn, et2, Arepeats, 180 BDrepeats, ABmix, source); 181 testFile = writeTestFile(tname+".java", sourceString); 182 // Compile test source and read classfile. 183 File classFile = null; 184 try { 185 classFile = compile(testFile); 186 System.out.println("pass compile: " + tname + ".java"); 187 } catch (Error err) { 188 System.err.println("fail compile. Source:\n" + sourceString); 189 throw err; 190 } 191 if(!compileonly) { 192 //check if innerClassname is set 193 String classdir = classFile.getAbsolutePath(); 194 if(source.innerClassname != null) { 195 StringBuffer sb = new StringBuffer(classdir); 196 classFile=new File(sb.insert(sb.lastIndexOf(".class"), 197 source.innerClassname).toString()); 198 source.innerClassname=null; 199 } else if (source.altClassName != null) { 200 classdir = classdir.substring(0,classdir.lastIndexOf("Test")); 201 classFile=new File(classdir.concat(source.altClassName)); 202 source.innerClassname=null; 203 } 204 ClassFile cf = ClassFile.read(classFile); 205 206 println("Testing classfile: " + cf.getName()); 207 //Test class,fields and method counts. 208 test(cf); 209 210 for (Field f : cf.fields) { 211 test(cf, f); 212 test(cf, f, true); 213 } 214 for (Method m: cf.methods) { 215 test(cf, m); 216 test(cf, m, true); 217 } 218 219 countAnnotations(); // sets errors=0 before counting. 220 if (errors > 0) { 221 System.err.println( testDef ); 222 System.err.println( "Source:\n" + sourceString ); 223 vFailures.add(testDef); 224 } 225 } 226 if(errors==0) println("Pass"); println(""); 227 } 228 229 /* 230 * Source definitions for test cases. 231 * To add a test: 232 * Add enum to srce(near top of file) with expected annotation counts. 233 * Add source defintion below. 234 */ 235 String sourceString(String testname, String retentn, String annot2, 236 Boolean Arepeats, Boolean BDrepeats, Boolean ABmix, 237 srce src) { 238 239 String As = "@A", Bs = "@B", Ds = "@D"; 240 if(Arepeats) As = "@A @A"; 241 if(BDrepeats) { 242 Bs = "@B @B"; 243 Ds = "@D @D"; 244 } 245 if(ABmix) { As = "@A @B"; Bs = "@A @B"; Ds = "@D @D"; } 246 247 // Source to check for TYPE_USE and TYPE_PARAMETER annotations. 248 // Source base (annotations) is same for all test cases. 249 String source = new String(); 250 String imports = new String("import java.lang.annotation.*; \n" + 251 "import static java.lang.annotation.RetentionPolicy.*; \n" + 252 "import static java.lang.annotation.ElementType.*; \n" + 253 "import java.util.List; \n" + 254 "import java.util.ArrayList;\n\n"); 255 256 String sourceBase = new String( 257 "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @Repeatable( AC.class ) @interface A { }\n" + 258 "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @interface AC { A[] value(); } \n" + 259 "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @Repeatable( BC.class ) @interface B { }\n" + 260 "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @interface BC { B[] value(); } \n" + 261 "@Retention("+retentn+") @Target({TYPE_USE,TYPE_PARAMETER,_OTHER_}) @Repeatable(DC.class) @interface D { }\n" + 262 "@Retention("+retentn+") @Target({TYPE_USE,TYPE_PARAMETER,_OTHER_}) @interface DC { D[] value(); }"); 263 264 // Test case sources with sample generated source 265 switch(src) { 266 case src1: //(repeating) type annotations on lambda expressions. 267 /* 268 * class Test1 { 269 * Test1(){} 270 * interface MapFun<T,R> { R m( T n); } 271 * void meth( MapFun<String,Integer> mf ) { 272 * assert( mf.m("four") == 4); 273 * } 274 * void test(Integer i) { 275 * // lambda expression as method arg 276 * meth( (@A @B String s) -> { @A @B Integer len = s.length(); return len; } ); 277 * }} 278 */ 279 source = new String( source + 280 "// " + src.description + "\n" + 281 "class " + testname + " {\n" + 282 " " + testname +"(){} \n" + 283 " interface MapFun<T,R> { R m( T n); }\n\n" + 284 " void meth( MapFun<String,Integer> mf ) {\n" + 285 " assert( mf.m(\"four\") == 4);\n" + 286 " }\n\n" + 287 " void test(Integer i) {\n" + 288 " // lambda expression as method arg\n" + 289 " meth( (_As_ _Bs_ String s) -> { _As_ _Bs_ Integer len = s.length(); return len; } );\n" + 290 "}}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 291 "\n"; 292 break; 293 case src2: //(repeating) type annotations on new in single line lambda expression. 294 /* 295 * //case2: (repeating) type annotations on new in single lambda expressions. 296 * class Test2{ 297 * interface MapFun<T, R> { R m( T n); } 298 * MapFun<Integer, String> its; 299 * void test(Integer i) { 300 * its = a -> "~"+new @A @B Integer(a).toString()+"~"; 301 * System.out.println("in: " + i + " out: " + its.m(i)); 302 * }} 303 */ 304 source = new String( source + 305 "// " + src.description + "\n" + 306 "class " + testname + "{\n" + 307 " interface MapFun<T, R> { R m( T n); }\n" + 308 " MapFun<Integer, String> its;\n" + 309 " void test(Integer i) {\n" + 310 " its = a -> \"~\"+new _As_ _Bs_ Integer(a).toString()+\"~\";\n" + 311 " System.out.println(\"in: \" + i + \" out: \" + its.m(i));\n" + 312 " }\n" + 313 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 314 "\n"; 315 break; 316 case src3: //(repeating) type annotations in lambda expression code block. 317 /* 318 * class Test183{ 319 * interface MapFun<T, R> { R m( T n); } 320 * MapFun<List<Integer>, String> iLs; 321 * void testm(Integer i) { 322 * iLs = l -> { @A @B @A @B String ret = new String(); 323 * for( @A @B @A @B Integer i2 : l) 324 * ret=ret.concat(i2.toString() + " "); 325 * return ret; }; 326 * List<Integer> li = new ArrayList<>(); 327 * for(int j=0; j<i; j++) li.add(j); 328 * System.out.println(iLs.m(li) ); 329 * }} 330 */ 331 source = new String( source + 332 "// " + src.description + "\n" + 333 "class "+ testname + "{\n" + 334 " interface MapFun<T, R> { R m( T n); }\n" + 335 " MapFun<List<Integer>, String> iLs;\n" + 336 " void testm(Integer i) {\n" + 337 " iLs = l -> { _As_ _Bs_ String ret = new String();\n" + 338 " for( _As_ _Bs_ Integer i2 : l)\n" + 339 " ret=ret.concat(i2.toString() + \" \");\n" + 340 " return ret; };\n" + 341 " List<Integer> li = new ArrayList<>();\n" + 342 " for(int j=0; j<i; j++) li.add(j);\n" + 343 " System.out.println(iLs.m(li) );\n" + 344 "}\n" + 345 "\n" + 346 " public static void main(String... args) {new " + testname + "().testm(5); }\n" + 347 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 348 "\n"; 349 break; 350 case src4: //(repeating) type annotations in code block with recursion,cast 351 /* 352 * class Test194{ 353 * interface MapFun<T, R> { R m( T n); } 354 * MapFun<Integer, Double> nf; 355 * void testm(Integer i) { 356 * nf = j -> { return j == 1 ? 1.0 : (@A @B @A @B Double)(nf.m(j-1) * j); }; 357 * System.out.println( "nf.m(" + i + "): " + nf.m(i)); 358 * } 359 * } 360 */ 361 source = new String( source + 362 "// " + src.description + "\n" + 363 "class "+ testname + "{\n" + 364 " interface MapFun<T, R> { R m( T n); }\n" + 365 " MapFun<Integer, Double> nf;\n" + 366 " void testm(Integer i) {\n" + 367 " nf = j -> { return j == 1 ? 1.0 : (_As_ _Bs_ Double)(nf.m(j-1) * j); };\n" + 368 " System.out.println( \"nf.m(\" + i + \"): \" + nf.m(i));\n" + 369 " }\n" + 370 " public static void main(String... args) {new " + testname + "().testm(5); }\n" + 371 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 372 "\n"; 373 break; 374 case src5: //(repeating) type annotations in lambda expression code block. 375 /* 376 * class Test180 { 377 * interface MapFun<T, R> { R m( T n); } 378 * MapFun<Integer,List<Integer>> iLi; 379 * void test(Integer i) { 380 * // type parameter use. 381 * iLi = n -> { List<@A @B @A @B Integer> LI = new ArrayList<@A @B @A @B Integer>(n); 382 * for(int nn = n; nn >=0; nn--) LI.add(nn); 383 * return LI; }; 384 * List<Integer> li = iLi.m(i); 385 * for(Integer k : li) System.out.print(k); 386 * } 387 * } 388 */ 389 source = new String( source + 390 "// " + src.description + "\n" + 391 "class "+ testname + "{\n" + 392 " interface MapFun<T, R> { R m( T n); }\n" + 393 " MapFun<Integer,List<Integer>> iLi;\n" + 394 " void test(Integer i) {\n" + 395 " // type parameter use.\n" + 396 " iLi = n -> { List<_As_ _Bs_ Integer> LI = new ArrayList<_As_ _Bs_ Integer>(n);\n" + 397 " for(int nn = n; nn >=0; nn--) LI.add(nn);\n" + 398 " return LI; };\n" + 399 " List<Integer> li = iLi.m(i);\n" + 400 " for(Integer k : li) System.out.print(k);\n" + 401 "}\n" + 402 " public static void main(String... args) {new " + testname + "().test(5); }\n" + 403 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs).replace("_Ds_",Ds) + 404 "\n"; 405 break; 406 case src6: //(repeating) type annotations on type parm in method reference. 407 /* 408 * class Test240{ 409 * interface PrintString { void print(String s); } 410 * public void printArray(Object[] oa, PrintString ps) { 411 * for(Object o : oa ) ps.print(o.toString()); 412 * } 413 * public void test() { 414 * Integer[] intarray = {1,2,3,4,5}; 415 * printArray(intarray, @A @B @A @B TPrint::<@A @B @A @B String>print); 416 * } 417 * } 418 * class TPrint { 419 * public static <T> void print(T t) { System.out.println( t.toString()); } 420 * } 421 */ 422 source = new String( source + 423 "// " + src.description + "\n" + 424 "class "+ testname + "{\n" + 425 " interface PrintString { void print(String s); }\n" + 426 " public void printArray(Object[] oa, PrintString ps) {\n" + 427 " for(Object o : oa ) ps.print(o.toString());\n" + 428 " }\n" + 429 " public void test() {\n" + 430 " Integer[] intarray = {1,2,3,4,5};\n" + 431 " printArray(intarray, _As_ _Bs_ TPrint::<_As_ _Bs_ String>print);\n" + 432 " }\n" + 433 " public static void main(String... args) {new " + testname + "().test(); }\n" + 434 "}\n\n" + 435 "class TPrint {\n" + 436 " public static <T> void print(T t) { System.out.println( t.toString()); }\n" + 437 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 438 "\n"; 439 break; 440 case src7: //(repeating)type annotations in inner class of lambda expression. 441 /* 442 * class Test2{ 443 * interface MapFun<T, R> { R m( T n); } 444 * MapFun<Class<?>,String> cs; 445 * void test() { 446 * cs = c -> { 447 * class innerClass { 448 * @A @B Class<?> icc = null; 449 * String getString() { return icc.toString(); } 450 * } 451 * return new innerClass().getString(); 452 * }; 453 * System.out.println("cs.m : " + cs.m(Integer.class)); 454 * } 455 * } 456 */ 457 source = new String( source + 458 "// " + src.description + "\n" + 459 "class "+ testname + "{\n" + 460 " interface MapFun<T, R> { R m( T n); }\n" + 461 " MapFun<Class<?>,String> cs;\n" + 462 " void test() {\n" + 463 " cs = c -> {\n" + 464 " class innerClass {\n" + 465 " _As_ _Bs_ Class<?> icc = null;\n" + 466 " innerClass(Class<?> _c) { icc = _c; }\n" + 467 " String getString() { return icc.toString(); }\n" + 468 " }\n" + 469 " return new innerClass(c).getString();\n" + 470 " };\n" + 471 " System.out.println(\"cs.m : \" + cs.m(Integer.class));\n" + 472 " }\n" + 473 "\n" + 474 " public static void main(String... args) {new " + testname + "().test(); }\n" + 475 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 476 "\n"; 477 src.innerClassname="$1innerClass"; 478 break; 479 case src8: //(repeating)type annotations in inner class of lambda expression. 480 /* 481 * class Test2{ 482 * interface MapFun<T, R> { R m( T n); } 483 * MapFun<Class<?>,String> cs; 484 * void test() { 485 * cs = c -> { 486 * class innerClass { 487 * Class<?> icc; 488 * innerClass(@A @B Class<?> _c) { icc = _c; } 489 * @A @B String getString() { return icc.toString(); } 490 * } 491 * return new innerClass(c).getString(); 492 * }; 493 * System.out.println("cs.m : " + cs.m(Integer.class)); 494 * } 495 * } 496 */ 497 source = new String( source + 498 "// " + src.description + "\n" + 499 "class "+ testname + "{\n" + 500 " interface MapFun<T, R> { R m( T n); }\n" + 501 " MapFun<Class<?>,String> cs;\n" + 502 " void test() {\n" + 503 " cs = c -> {\n" + 504 " class innerClass {\n" + 505 " Class<?> icc;\n" + 506 " innerClass(_As_ _Bs_ Class<?> _c) { icc = _c; }\n" + 507 " _As_ _Bs_ String getString() { return icc.toString(); }\n" + 508 " }\n" + 509 " return new innerClass(c).getString();\n" + 510 " };\n" + 511 " System.out.println(\"cs.m : \" + cs.m(Integer.class));\n" + 512 " }\n" + 513 "\n" + 514 " public static void main(String... args) {new " + testname + "().test(); }\n" + 515 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 516 "\n"; 517 src.innerClassname="$1innerClass"; 518 break; 519 case src9: //(repeating)type annotations on static method of interface 520 /* 521 * class Test90{ 522 * interface I { 523 * static @A @B @A @B String m() { @A @B @A @B String ret = "I.m"; return ret; } 524 * } 525 * } 526 */ 527 source = new String( source + 528 "// " + src.description + "\n" + 529 "class "+ testname + "{\n" + 530 " interface I { \n" + 531 " static _As_ _Bs_ String m() { _As_ _Bs_ String ret = \"I.m\"; return ret; }\n" + 532 " }\n" + 533 "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + 534 "\n"; 535 src.innerClassname="$I"; 536 break; 537 } 538 return imports + source; 539 } 540} 541