1 /*
2  * Copyright (c) 2008, 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 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 {
main(String[] args)36     public static void main(String[] args) throws Exception {
37         new Presence().run();
38     }
39 
run()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 
test(ClassFile cf)60     void test(ClassFile cf) {
61         test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
62         test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
63     }
64 
test(ClassFile cf, Method m)65     void test(ClassFile cf, Method m) {
66         test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
67         test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
68     }
69 
test(ClassFile cf, Field m)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
test(ClassFile cf, String name, boolean visible)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
test(ClassFile cf, Method m, String name, boolean visible)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
test(ClassFile cf, Field m, String name, boolean visible)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 
writeTestFile()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 
compileTestFile(File f)182     File compileTestFile(File f) {
183         int rc = com.sun.tools.javac.Main.compile(new String[] { "-source", "1.8", "-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 
countAnnotations()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 }
219