1 /*
   2  * Copyright (c) 2008, 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.io.*;
  25 import java.lang.annotation.ElementType;
  26 
  27 import com.sun.tools.classfile.*;
  28 
  29 /*
  30  * @test Presence
  31  * @bug 6843077
  32  * @summary test that all type annotations are present in the classfile
  33  */
  34 
  35 public class Presence {
  36     public static void main(String[] args) throws Exception {
  37         new Presence().run();
  38     }
  39 
  40     public void run() throws Exception {
  41         File javaFile = writeTestFile();
  42         File classFile = compileTestFile(javaFile);
  43 
  44         ClassFile cf = ClassFile.read(classFile);
  45         test(cf);
  46         for (Field f : cf.fields) {
  47             test(cf, f);
  48         }
  49         for (Method m: cf.methods) {
  50             test(cf, m);
  51         }
  52 
  53         countAnnotations();
  54 
  55         if (errors > 0)
  56             throw new Exception(errors + " errors found");
  57         System.out.println("PASSED");
  58     }
  59 
  60     void test(ClassFile cf) {
  61         test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
  62         test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
  63     }
  64 
  65     void test(ClassFile cf, Method m) {
  66         test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
  67         test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
  68     }
  69 
  70     void test(ClassFile cf, Field m) {
  71         test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
  72         test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
  73     }
  74 
  75     // test the result of Attributes.getIndex according to expectations
  76     // encoded in the method's name
  77     void test(ClassFile cf, String name, boolean visible) {
  78         int index = cf.attributes.getIndex(cf.constant_pool, name);
  79         if (index != -1) {
  80             Attribute attr = cf.attributes.get(index);
  81             assert attr instanceof RuntimeTypeAnnotations_attribute;
  82             RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
  83             all += tAttr.annotations.length;
  84             if (visible)
  85                 visibles += tAttr.annotations.length;
  86             else
  87                 invisibles += tAttr.annotations.length;
  88         }
  89     }
  90 
  91     // test the result of Attributes.getIndex according to expectations
  92     // encoded in the method's name
  93     void test(ClassFile cf, Method m, String name, boolean visible) {
  94         Attribute attr = null;
  95         Code_attribute cAttr = null;
  96         RuntimeTypeAnnotations_attribute tAttr = null;
  97 
  98         // collect annotations attributes on method
  99         int index = m.attributes.getIndex(cf.constant_pool, name);
 100         if (index != -1) {
 101             attr = m.attributes.get(index);
 102             assert attr instanceof RuntimeTypeAnnotations_attribute;
 103             tAttr = (RuntimeTypeAnnotations_attribute)attr;
 104             all += tAttr.annotations.length;
 105             if (visible)
 106                 visibles += tAttr.annotations.length;
 107             else
 108                 invisibles += tAttr.annotations.length;
 109         }
 110         // collect annotations from method's code attribute
 111         index = m.attributes.getIndex(cf.constant_pool, Attribute.Code);
 112         if(index!= -1) {
 113             attr = m.attributes.get(index);
 114             assert attr instanceof Code_attribute;
 115             cAttr = (Code_attribute)attr;
 116             index = cAttr.attributes.getIndex(cf.constant_pool, name);
 117             if(index!= -1) {
 118                 attr = cAttr.attributes.get(index);
 119                 assert attr instanceof RuntimeTypeAnnotations_attribute;
 120                 tAttr = (RuntimeTypeAnnotations_attribute)attr;
 121                 all += tAttr.annotations.length;
 122                 if (visible)
 123                     visibles += tAttr.annotations.length;
 124                 else
 125                     invisibles += tAttr.annotations.length;
 126                }
 127         }
 128     }
 129 
 130     // test the result of Attributes.getIndex according to expectations
 131     // encoded in the method's name
 132     void test(ClassFile cf, Field m, String name, boolean visible) {
 133         int index = m.attributes.getIndex(cf.constant_pool, name);
 134         if (index != -1) {
 135             Attribute attr = m.attributes.get(index);
 136             assert attr instanceof RuntimeTypeAnnotations_attribute;
 137             RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
 138             all += tAttr.annotations.length;
 139             if (visible)
 140                 visibles += tAttr.annotations.length;
 141             else
 142                 invisibles += tAttr.annotations.length;
 143         }
 144     }
 145 
 146     File writeTestFile() throws IOException {
 147         File f = new File("TestPresence.java");
 148         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
 149         out.println("import java.util.*;");
 150         out.println("import java.lang.annotation.*;");
 151 
 152         out.println("class TestPresence<@TestPresence.A T extends @TestPresence.A List<@TestPresence.A String>> { ");
 153         out.println("  @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})");
 154         out.println("  @interface A { }");
 155 
 156         out.println("  Map<@A String, Map<@A String, @A String>> f1;");
 157 
 158         out.println("  <@A TM extends @A List<@A String>>");
 159         out.println("  Map<@A String, @A List<@A String>>");
 160         out.println("  method(@A TestPresence<T> this, List<@A String> @A [] param1, String @A [] @A ... param2)");
 161         out.println("  throws @A Exception {");
 162         out.println("    @A String lc1 = null;");
 163         out.println("    @A List<@A String> lc2 = null;");
 164         out.println("    @A String @A [] [] @A[] lc3 = null;");
 165         out.println("    List<? extends @A List<@A String>> lc4 = null;");
 166         out.println("    Object lc5 = (@A List<@A String>) null;");
 167         out.println("    boolean lc6 = lc1 instanceof @A String;");
 168         out.println("    boolean lc7 = lc5 instanceof @A String @A [] @A [];");
 169         out.println("    new @A ArrayList<@A String>();");
 170         out.println("    Object lc8 = new @A String @A [4];");
 171         out.println("    try {");
 172         out.println("      Object lc10 = int.class;");
 173         out.println("    } catch (@A Exception e) { e.toString(); }");
 174         out.println("    return null;");
 175         out.println("  }");
 176         out.println("  void vararg1(String @A ... t) { } ");
 177         out.println("}");
 178         out.close();
 179         return f;
 180     }
 181 
 182     File compileTestFile(File f) {
 183         int rc = com.sun.tools.javac.Main.compile(new String[] {"-g", f.getPath() });
 184         if (rc != 0)
 185             throw new Error("compilation failed. rc=" + rc);
 186         String path = f.getPath();
 187         return new File(path.substring(0, path.length() - 5) + ".class");
 188     }
 189 
 190     void countAnnotations() {
 191         int expected_visibles = 0, expected_invisibles = 38;
 192         int expected_all = expected_visibles + expected_invisibles;
 193 
 194         if (expected_all != all) {
 195             errors++;
 196             System.err.println("expected " + expected_all
 197                     + " annotations but found " + all);
 198         }
 199 
 200         if (expected_visibles != visibles) {
 201             errors++;
 202             System.err.println("expected " + expected_visibles
 203                     + " visibles annotations but found " + visibles);
 204         }
 205 
 206         if (expected_invisibles != invisibles) {
 207             errors++;
 208             System.err.println("expected " + expected_invisibles
 209                     + " invisibles annotations but found " + invisibles);
 210         }
 211 
 212     }
 213 
 214     int errors;
 215     int all;
 216     int visibles;
 217     int invisibles;
 218 }