1 /*
   2  * Copyright (c) 2012, 2014, 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 import java.lang.annotation.*;
  25 import java.io.*;
  26 import java.net.URL;
  27 import java.util.List;
  28 
  29 import com.sun.tools.classfile.*;
  30 
  31 public class ClassfileTestHelper {
  32     int expected_tinvisibles = 0;
  33     int expected_tvisibles = 0;
  34     int expected_invisibles = 0;
  35     int expected_visibles = 0;
  36 
  37     //Makes debugging much easier. Set to 'false' for less output.
  38     public Boolean verbose = true;
  39     void println(String msg) { if (verbose) System.out.println(msg); }
  40     void print(String msg) { if (verbose) System.out.print(msg); }
  41 
  42     File writeTestFile(String fname, String source) throws IOException {
  43       File f = new File(fname);
  44         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
  45         out.println(source);
  46         out.close();
  47         return f;
  48     }
  49 
  50     File compile(File f) {
  51         int rc = com.sun.tools.javac.Main.compile(new String[] {
  52                 "-g", f.getPath() });
  53         if (rc != 0)
  54             throw new Error("compilation failed. rc=" + rc);
  55         String path = f.getPath();
  56         return new File(path.substring(0, path.length() - 5) + ".class");
  57     }
  58 
  59     ClassFile getClassFile(String name) throws IOException, ConstantPoolException {
  60         URL url = getClass().getResource(name);
  61         InputStream in = url.openStream();
  62         try {
  63             return ClassFile.read(in);
  64         } finally {
  65             in.close();
  66         }
  67     }
  68 
  69     ClassFile getClassFile(URL url) throws IOException, ConstantPoolException {
  70         InputStream in = url.openStream();
  71         try {
  72             return ClassFile.read(in);
  73         } finally {
  74             in.close();
  75         }
  76     }
  77 
  78     /************ Helper annotations counting methods ******************/
  79     void test(ClassFile cf) {
  80         test("CLASS",cf, null, null, Attribute.RuntimeVisibleTypeAnnotations, true);
  81         test("CLASS",cf, null, null, Attribute.RuntimeInvisibleTypeAnnotations, false);
  82         //RuntimeAnnotations since one annotation can result in two attributes.
  83         test("CLASS",cf, null, null, Attribute.RuntimeVisibleAnnotations, true);
  84         test("CLASS",cf, null, null, Attribute.RuntimeInvisibleAnnotations, false);
  85     }
  86 
  87     void test(ClassFile cf, Field f, Boolean local) {
  88         if (!local) {
  89             test("FIELD",cf, f, null, Attribute.RuntimeVisibleTypeAnnotations, true);
  90             test("FIELD",cf, f, null, Attribute.RuntimeInvisibleTypeAnnotations, false);
  91             test("FIELD",cf, f, null, Attribute.RuntimeVisibleAnnotations, true);
  92             test("FIELD",cf, f, null, Attribute.RuntimeInvisibleAnnotations, false);
  93         } else {
  94             test("CODE",cf, f, null, Attribute.RuntimeVisibleTypeAnnotations, true);
  95             test("CODE",cf, f, null, Attribute.RuntimeInvisibleTypeAnnotations, false);
  96             test("CODE",cf, f, null, Attribute.RuntimeVisibleAnnotations, true);
  97             test("CODE",cf, f, null, Attribute.RuntimeInvisibleAnnotations, false);
  98         }
  99     }
 100 
 101     void test(ClassFile cf, Field f) {
 102         test(cf, f, false);
 103     }
 104 
 105     // 'local' determines whether to look for annotations in code attribute or not.
 106     void test(ClassFile cf, Method m, Boolean local) {
 107         if (!local) {
 108             test("METHOD",cf, null, m, Attribute.RuntimeVisibleTypeAnnotations, true);
 109             test("METHOD",cf, null, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
 110             test("METHOD",cf, null, m, Attribute.RuntimeVisibleAnnotations, true);
 111             test("METHOD",cf, null, m, Attribute.RuntimeInvisibleAnnotations, false);
 112         } else  {
 113             test("MCODE",cf, null, m, Attribute.RuntimeVisibleTypeAnnotations, true);
 114             test("MCODE",cf, null, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
 115             test("MCODE",cf, null, m, Attribute.RuntimeVisibleAnnotations, true);
 116             test("MCODE",cf, null, m, Attribute.RuntimeInvisibleAnnotations, false);
 117         }
 118     }
 119 
 120     // default to not looking in code attribute
 121     void test(ClassFile cf, Method m ) {
 122         test(cf, m, false);
 123     }
 124 
 125     // Test the result of Attributes.getIndex according to expectations
 126     // encoded in the class/field/method name; increment annotations counts.
 127     void test(String ttype, ClassFile cf, Field f, Method m, String annName, boolean visible) {
 128         String testtype = ttype;
 129         String name = null;
 130         int index = -1;
 131         Attribute attr = null;
 132         Code_attribute cAttr = null;
 133         boolean isTAattr = annName.contains("TypeAnnotations");
 134         try {
 135             switch(testtype) {
 136                 case "FIELD":
 137                     name = f.getName(cf.constant_pool);
 138                     index = f.attributes.getIndex(cf.constant_pool, annName);
 139                     if(index!= -1)
 140                         attr = f.attributes.get(index);
 141                     break;
 142                 case "CODE":
 143                     name = f.getName(cf.constant_pool);
 144                     //fetch index of and code attribute and annotations from code attribute.
 145                     index = cf.attributes.getIndex(cf.constant_pool, Attribute.Code);
 146                     if(index!= -1) {
 147                         attr = cf.attributes.get(index);
 148                         assert attr instanceof Code_attribute;
 149                         cAttr = (Code_attribute)attr;
 150                         index = cAttr.attributes.getIndex(cf.constant_pool, annName);
 151                         if(index!= -1)
 152                             attr = cAttr.attributes.get(index);
 153                     }
 154                     break;
 155                 case "METHOD":
 156                     name = m.getName(cf.constant_pool);
 157                     index = m.attributes.getIndex(cf.constant_pool, annName);
 158                     if(index!= -1)
 159                         attr = m.attributes.get(index);
 160                     break;
 161                 case "MCODE":
 162                     name = m.getName(cf.constant_pool);
 163                     //fetch index of and code attribute and annotations from code attribute.
 164                     index = m.attributes.getIndex(cf.constant_pool, Attribute.Code);
 165                     if(index!= -1) {
 166                         attr = m.attributes.get(index);
 167                         assert attr instanceof Code_attribute;
 168                         cAttr = (Code_attribute)attr;
 169                         index = cAttr.attributes.getIndex(cf.constant_pool, annName);
 170                         if(index!= -1)
 171                             attr = cAttr.attributes.get(index);
 172                     }
 173                     break;
 174                 default:
 175                     name = cf.getName();
 176                     index = cf.attributes.getIndex(cf.constant_pool, annName);
 177                     if(index!= -1) attr = cf.attributes.get(index);
 178             }
 179         } catch(ConstantPoolException cpe) { cpe.printStackTrace(); }
 180 
 181         if (index != -1) {
 182             if(isTAattr) { //count RuntimeTypeAnnotations
 183                 RuntimeTypeAnnotations_attribute tAttr =
 184                         (RuntimeTypeAnnotations_attribute)attr;
 185                 println(testtype + ": " + name + ", " + annName + ": " +
 186                         tAttr.annotations.length );
 187                 if (tAttr.annotations.length > 0) {
 188                     for (int i = 0; i < tAttr.annotations.length; i++) {
 189                         println("  types:" + tAttr.annotations[i].position.type);
 190                     }
 191                 } else {
 192                     println("");
 193                 }
 194                 allt += tAttr.annotations.length;
 195                 if (visible)
 196                     tvisibles += tAttr.annotations.length;
 197                 else
 198                     tinvisibles += tAttr.annotations.length;
 199             } else {
 200                 RuntimeAnnotations_attribute tAttr =
 201                         (RuntimeAnnotations_attribute)attr;
 202                 println(testtype + ": " + name + ", " + annName + ": " +
 203                         tAttr.annotations.length );
 204                 all += tAttr.annotations.length;
 205                 if (visible)
 206                     visibles += tAttr.annotations.length;
 207                 else
 208                     invisibles += tAttr.annotations.length;
 209             }
 210         }
 211     }
 212 
 213     void countAnnotations() {
 214         errors=0;
 215         int expected_allt = expected_tvisibles + expected_tinvisibles;
 216         int expected_all = expected_visibles + expected_invisibles;
 217 
 218         if (expected_allt != allt) {
 219             errors++;
 220             System.err.println("Failure: expected " + expected_allt +
 221                     " type annotations but found " + allt);
 222         }
 223         if (expected_all != all) {
 224             errors++;
 225             System.err.println("Failure: expected " + expected_all +
 226                     " annotations but found " + all);
 227         }
 228         if (expected_tvisibles != tvisibles) {
 229             errors++;
 230             System.err.println("Failure: expected " + expected_tvisibles +
 231                     " typevisible annotations but found " + tvisibles);
 232         }
 233 
 234         if (expected_tinvisibles != tinvisibles) {
 235             errors++;
 236             System.err.println("Failure: expected " + expected_tinvisibles +
 237                     " typeinvisible annotations but found " + tinvisibles);
 238         }
 239         allt=0;
 240         tvisibles=0;
 241         tinvisibles=0;
 242         all=0;
 243         visibles=0;
 244         invisibles=0;
 245     }
 246 
 247     int errors;
 248     int allt;
 249     int tvisibles;
 250     int tinvisibles;
 251     int all;
 252     int visibles;
 253     int invisibles;
 254 }