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