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 }