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 */ 23 24 /* 25 * @test 26 * @bug 8005085 8008762 8008751 8013065 8015323 8015257 27 * @summary Type annotations on anonymous and inner class. 28 * Six TYPE_USE annotations are repeated(or not); Four combinations create 29 * four test files, and each results in the test class and 2 anonymous classes. 30 * Each element of these three classes is checked for expected number of the 31 * four annotation Attributes. Expected annotation counts depend on type of 32 * annotation place on type of element (a FIELD&TYPE_USE element on a field 33 * results in 2). Elements with no annotations expect 0. 34 * Source template is read in from testanoninner.template 35 * 36 */ 37 import java.lang.annotation.*; 38 import java.io.*; 39 import java.util.List; 40 import com.sun.tools.classfile.*; 41 import java.nio.file.Files; 42 import java.nio.charset.*; 43 import java.io.File; 44 import java.io.IOException; 45 46 47 import java.lang.annotation.*; 48 import static java.lang.annotation.RetentionPolicy.*; 49 import static java.lang.annotation.ElementType.*; 50 51 /* 52 * A source template is read in and testname and annotations are inserted 53 * via replace(). 54 */ 55 public class TestAnonInnerClasses extends ClassfileTestHelper { 56 // tally errors and test cases 57 int errors = 0; 58 int checks = 0; 59 //Note expected test count in case of skips due to bugs. 60 int tc = 0, xtc = 180; // 45 x 4 variations of repeated annotations. 61 File testSrc = new File(System.getProperty("test.src")); 62 63 String[] AnnoAttributes = { 64 Attribute.RuntimeVisibleTypeAnnotations, 65 Attribute.RuntimeInvisibleTypeAnnotations, 66 Attribute.RuntimeVisibleAnnotations, 67 Attribute.RuntimeInvisibleAnnotations 68 }; 69 70 // template for source files 71 String srcTemplate = "testanoninner.template"; 72 73 // Four test files generated based on combinations of repeating annotations. 74 Boolean As= false, Bs=true, Cs=false, Ds=false, TAs=false,TBs=false; 75 Boolean [][] bRepeat = new Boolean[][]{ 76 /* no repeats */ {false, false, false, false, false, false}, 77 /* repeat A,C,TA */ {true, false, true, false, true, false}, 78 /* repeat B,D,TB */ {false, true, false, true, false, true}, 79 /* repeat all */ {true, true, true, true, true, true} 80 }; 81 // Save descriptions of failed test case; does not terminate upon a failure. 82 List<String> failed = new java.util.LinkedList<>(); 83 84 public static void main(String[] args) throws Exception { 85 new TestAnonInnerClasses().run(); 86 } 87 88 // Check annotation counts and make reports sufficiently descriptive to 89 // easily diagnose. 90 void check(String testcase, int vtaX, int itaX, int vaX, int iaX, 91 int vtaA, int itaA, int vaA, int iaA) { 92 93 String descr = " checking " + testcase+" _TYPE_, expected: " + 94 vtaX + ", " + itaX + ", " + vaX + ", " + iaX + "; actual: " + 95 vtaA + ", " + itaA + ", " + vaA + ", " + iaA; 96 String description; 97 description=descr.replace("_TYPE_","RuntimeVisibleTypeAnnotations"); 98 if(vtaX != vtaA) { 99 errors++; 100 failed.add(++checks + " " + testcase + ": (vtaX) " + vtaX + 101 " != " + vtaA + " (vtaA)"); 102 println(checks + " FAIL: " + description); 103 } else println(++checks + " PASS: " + description); 104 description=descr.replace("_TYPE_","RuntimeInvisibleTypeAnnotations"); 105 if(itaX != itaA) { 106 errors++; 107 failed.add(++checks + " " + testcase + ": (itaX) " + itaX + " != " + 108 itaA + " (itaA)"); 109 println(checks + " FAIL: " + description); 110 } else println(++checks + " PASS: " + description); 111 description=descr.replace("_TYPE_","RuntimeVisibleAnnotations"); 112 if(vaX != vaA) { 113 errors++; 114 failed.add(++checks + " " + testcase + ": (vaX) " + vaX + " != " + 115 vaA + " (vaA)"); 116 println(checks + " FAIL: " + description); 117 } else println(++checks + " PASS: " + description); 118 description=descr.replace("_TYPE_","RuntimeInvisibleAnnotations"); 119 if(iaX != iaA) { 120 errors++; 121 failed.add(++checks + " " + testcase + ": (iaX) " + iaX + " != " + 122 iaA + " (iaA)"); 123 println(checks + " FAIL: " + description); 124 } else println(++checks + " PASS: " + description); 125 println(""); 126 } 127 128 // Print failed cases (if any) and throw exception for fail. 129 void report() { 130 if(errors!=0) { 131 System.err.println("Failed tests: " + errors + 132 "\nfailed test cases:\n"); 133 for(String t: failed) System.err.println(" " + t); 134 throw new RuntimeException("FAIL: There were test failures."); 135 } else 136 System.out.println("PASSED all tests."); 137 } 138 139 void test(String ttype, ClassFile cf, Method m, Field f, boolean visible) { 140 int vtaActual = 0, itaActual = 0, vaActual = 0, iaActual = 0, 141 vtaExp = 0, itaExp = 0, vaExp = 0, iaExp = 0, 142 index = 0, index2 = 0; 143 String memberName = null, testcase = "undefined", testClassName = null; 144 Attribute attr = null, cattr = null; 145 Code_attribute CAttr = null; 146 // Get counts of 4 annotation Attributes on element being checked. 147 for (String AnnoType : AnnoAttributes) { 148 try { 149 switch(ttype) { 150 case "METHOD": 151 index = m.attributes.getIndex(cf.constant_pool, 152 AnnoType); 153 memberName = m.getName(cf.constant_pool); 154 if(index != -1) 155 attr = m.attributes.get(index); 156 //fetch index annotations from code attribute. 157 index2 = m.attributes.getIndex(cf.constant_pool, 158 Attribute.Code); 159 if(index2 != -1) { 160 cattr = m.attributes.get(index2); 161 assert cattr instanceof Code_attribute; 162 CAttr = (Code_attribute)cattr; 163 index2 = CAttr.attributes.getIndex(cf.constant_pool, 164 AnnoType); 165 if(index2 != -1) 166 cattr = CAttr.attributes.get(index2); 167 } 168 break; 169 case "FIELD": 170 index = f.attributes.getIndex(cf.constant_pool, 171 AnnoType); 172 memberName = f.getName(cf.constant_pool); 173 if(index != -1) 174 attr = f.attributes.get(index); 175 //fetch index annotations from code attribute. 176 index2 = cf.attributes.getIndex(cf.constant_pool, 177 Attribute.Code); 178 if(index2!= -1) { 179 cattr = cf.attributes.get(index2); 180 assert cattr instanceof Code_attribute; 181 CAttr = (Code_attribute)cattr; 182 index2 = CAttr.attributes.getIndex(cf.constant_pool, 183 AnnoType); 184 if(index2!= -1) 185 cattr = CAttr.attributes.get(index2); 186 } 187 break; 188 189 default: 190 memberName = cf.getName(); 191 index = cf.attributes.getIndex(cf.constant_pool, 192 AnnoType); 193 if(index!= -1) attr = cf.attributes.get(index); 194 break; 195 } 196 } catch(ConstantPoolException cpe) { cpe.printStackTrace(); } 197 try { 198 testClassName=cf.getName(); 199 testcase = ttype + ": " + testClassName + ": " + 200 memberName + ", "; 201 } catch(ConstantPoolException cpe) { cpe.printStackTrace(); } 202 if(index != -1) { 203 switch(AnnoType) { 204 case Attribute.RuntimeVisibleTypeAnnotations: 205 //count RuntimeVisibleTypeAnnotations 206 RuntimeVisibleTypeAnnotations_attribute RVTAa = 207 (RuntimeVisibleTypeAnnotations_attribute)attr; 208 vtaActual += RVTAa.annotations.length; 209 break; 210 case Attribute.RuntimeVisibleAnnotations: 211 //count RuntimeVisibleAnnotations 212 RuntimeVisibleAnnotations_attribute RVAa = 213 (RuntimeVisibleAnnotations_attribute)attr; 214 vaActual += RVAa.annotations.length; 215 break; 216 case Attribute.RuntimeInvisibleTypeAnnotations: 217 //count RuntimeInvisibleTypeAnnotations 218 RuntimeInvisibleTypeAnnotations_attribute RITAa = 219 (RuntimeInvisibleTypeAnnotations_attribute)attr; 220 itaActual += RITAa.annotations.length; 221 break; 222 case Attribute.RuntimeInvisibleAnnotations: 223 //count RuntimeInvisibleAnnotations 224 RuntimeInvisibleAnnotations_attribute RIAa = 225 (RuntimeInvisibleAnnotations_attribute)attr; 226 iaActual += RIAa.annotations.length; 227 break; 228 } 229 } 230 // annotations from code attribute. 231 if(index2 != -1) { 232 switch(AnnoType) { 233 case Attribute.RuntimeVisibleTypeAnnotations: 234 //count RuntimeVisibleTypeAnnotations 235 RuntimeVisibleTypeAnnotations_attribute RVTAa = 236 (RuntimeVisibleTypeAnnotations_attribute)cattr; 237 vtaActual += RVTAa.annotations.length; 238 break; 239 case Attribute.RuntimeVisibleAnnotations: 240 //count RuntimeVisibleAnnotations 241 RuntimeVisibleAnnotations_attribute RVAa = 242 (RuntimeVisibleAnnotations_attribute)cattr; 243 vaActual += RVAa.annotations.length; 244 break; 245 case Attribute.RuntimeInvisibleTypeAnnotations: 246 //count RuntimeInvisibleTypeAnnotations 247 RuntimeInvisibleTypeAnnotations_attribute RITAa = 248 (RuntimeInvisibleTypeAnnotations_attribute)cattr; 249 itaActual += RITAa.annotations.length; 250 break; 251 case Attribute.RuntimeInvisibleAnnotations: 252 //count RuntimeInvisibleAnnotations 253 RuntimeInvisibleAnnotations_attribute RIAa = 254 (RuntimeInvisibleAnnotations_attribute)cattr; 255 iaActual += RIAa.annotations.length; 256 break; 257 } 258 } 259 } 260 261 switch ( memberName ) { 262 //METHODs 263 case "test" : vtaExp=4; itaExp=4; vaExp=0; iaExp=0; tc++; break; 264 case "mtest": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 265 case "m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 266 case "m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 267 case "m3": vtaExp=10; itaExp=10; vaExp=1; iaExp=1; tc++; break; 268 case "tm": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 269 //inner class 270 case "i_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 271 case "i_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 272 case "i_um": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 273 //local class 274 case "l_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 275 case "l_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 276 case "l_um": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 277 //anon class 278 case "mm_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 279 case "mm_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 280 case "mm_m3": vtaExp=10; itaExp=10;vaExp=1; iaExp=1; tc++; break; 281 case "mm_tm": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 282 //InnerAnon class 283 case "ia_m1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 284 case "ia_m2": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 285 case "ia_um": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 286 //FIELDs 287 case "data": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 288 case "odata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 289 case "pdata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 290 case "tdata": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 291 case "sa1": vtaExp = 6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 292 //inner class 293 case "i_odata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 294 case "i_pdata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 295 case "i_udata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 296 case "i_sa1": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 297 case "i_tdata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 298 //local class 299 case "l_odata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 300 case "l_pdata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 301 case "l_udata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 302 case "l_sa1": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 303 case "l_tdata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 304 //anon class 305 case "mm_odata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 306 case "mm_pdata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 307 case "mm_sa1": vtaExp = 6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 308 case "mm_tdata": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 309 // InnerAnon class 310 case "ia_odata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 311 case "ia_pdata1": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 312 case "ia_udata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 313 case "ia_sa1": vtaExp=6; itaExp=6; vaExp=1; iaExp=1; tc++; break; 314 case "ia_tdata": vtaExp=2; itaExp=2; vaExp=1; iaExp=1; tc++; break; 315 case "IA": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 316 case "IN": vtaExp=4; itaExp=4; vaExp=1; iaExp=1; tc++; break; 317 // default cases are <init>, this$0, this$1, mmtest, atest 318 default: vtaExp = 0; itaExp=0; vaExp=0; iaExp=0; break; 319 } 320 check(testcase,vtaExp, itaExp, vaExp, iaExp, 321 vtaActual,itaActual,vaActual,iaActual); 322 } 323 324 public void run() { 325 ClassFile cf = null; 326 InputStream in = null; 327 int testcount = 1; 328 File testFile = null; 329 // Generate source, check methods and fields for each combination. 330 for(Boolean[] bCombo : bRepeat) { 331 As=bCombo[0]; Bs=bCombo[1]; Cs=bCombo[2]; 332 Ds=bCombo[3]; TAs=bCombo[4]; TBs=bCombo[5]; 333 String testname = "Test" + testcount++; 334 println("Combinations: " + As + ", " + Bs + ", " + Cs + ", " + Ds + 335 ", " + TAs + ", " + TBs + 336 "; see " + testname + ".java"); 337 String[] classes = {testname + ".class", 338 testname + "$Inner.class", 339 testname + "$1Local1.class", 340 testname + "$1.class", 341 testname + "$1$1.class", 342 testname + "$1$InnerAnon.class" 343 }; 344 // Create test source, create and compile File. 345 String sourceString = getSource(srcTemplate, testname, 346 As, Bs, Cs, Ds, TAs, TBs); 347 System.out.println(sourceString); 348 try { 349 testFile = writeTestFile(testname+".java", sourceString); 350 } catch( java.io.IOException ioe) { ioe.printStackTrace(); } 351 // Compile test source and read classfile. 352 File classFile = null; 353 try { 354 classFile = compile(testFile); 355 } catch (Error err) { 356 System.err.println("FAILED compile. Source:\n" + sourceString); 357 throw err; 358 } 359 String testloc = classFile.getAbsolutePath().substring( 360 0,classFile.getAbsolutePath().indexOf(classFile.getPath())); 361 for(String clazz : classes) { 362 try { 363 cf = ClassFile.read(new File(testloc+clazz)); 364 } catch(Exception e) { e.printStackTrace(); } 365 // Test for all methods and fields 366 for (Method m: cf.methods) { 367 test("METHOD", cf, m, null, true); 368 } 369 for (Field f: cf.fields) { 370 test("FIELD", cf, null, f, true); 371 } 372 } 373 } 374 report(); 375 if(tc!=xtc) System.out.println("Test Count: " + tc + " != " + 376 "expected: " + xtc); 377 } 378 379 380 String getSrcTemplate(String sTemplate) { 381 List<String> tmpl = null; 382 String sTmpl = ""; 383 try { 384 tmpl = Files.readAllLines( new File(testSrc,sTemplate).toPath(), 385 Charset.defaultCharset()); 386 } catch ( IOException ioe ) { 387 String error = "FAILED: Test failed to read template" + sTemplate; 388 ioe.printStackTrace(); 389 throw new RuntimeException(error); 390 } 391 for(String l : tmpl) 392 sTmpl=sTmpl.concat(l).concat("\n"); 393 return sTmpl; 394 } 395 396 // test class template 397 String getSource(String templateName, String testname, 398 Boolean Arepeats, Boolean Brepeats, 399 Boolean Crepeats, Boolean Drepeats, 400 Boolean TArepeats, Boolean TBrepeats ) { 401 String As = Arepeats ? "@A @A":"@A", 402 Bs = Brepeats ? "@B @B":"@B", 403 Cs = Crepeats ? "@C @C":"@C", 404 Ds = Drepeats ? "@D @D":"@D", 405 TAs = TArepeats ? "@TA @TA":"@TA", 406 TBs = TBrepeats ? "@TB @TB":"@TB"; 407 408 // split up replace() lines for readability 409 String testsource = getSrcTemplate(templateName).replace("testname",testname); 410 testsource = testsource.replace("_As",As).replace("_Bs",Bs).replace("_Cs",Cs); 411 testsource = testsource.replace("_Ds",Ds).replace("_TAs",TAs).replace("_TBs",TBs); 412 return testsource; 413 } 414 }