author | aeremeev |
Fri, 06 Jun 2014 16:08:46 -0400 | |
changeset 24896 | 986d876a9121 |
parent 17578 | 46ac954e4a84 |
permissions | -rw-r--r-- |
15385 | 1 |
/* |
17578 | 2 |
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. |
15385 | 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.util.ArrayList; |
|
25 |
import java.util.Arrays; |
|
26 |
import java.util.List; |
|
27 |
import java.util.Map; |
|
28 |
||
29 |
import com.sun.tools.classfile.Attribute; |
|
30 |
import com.sun.tools.classfile.ClassFile; |
|
17578 | 31 |
import com.sun.tools.classfile.Code_attribute; |
15385 | 32 |
import com.sun.tools.classfile.TypeAnnotation; |
33 |
import com.sun.tools.classfile.Field; |
|
34 |
import com.sun.tools.classfile.Method; |
|
35 |
import com.sun.tools.classfile.RuntimeTypeAnnotations_attribute; |
|
36 |
import com.sun.tools.classfile.ConstantPool.InvalidIndex; |
|
37 |
import com.sun.tools.classfile.ConstantPool.UnexpectedEntry; |
|
38 |
||
39 |
public class ReferenceInfoUtil { |
|
40 |
||
41 |
public static final int IGNORE_VALUE = -321; |
|
42 |
||
43 |
public static List<TypeAnnotation> extendedAnnotationsOf(ClassFile cf) { |
|
24896
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
44 |
List<TypeAnnotation> annos = new ArrayList<>(); |
15385 | 45 |
findAnnotations(cf, annos); |
46 |
return annos; |
|
47 |
} |
|
48 |
||
49 |
/////////////////// Extract type annotations ////////////////// |
|
50 |
private static void findAnnotations(ClassFile cf, List<TypeAnnotation> annos) { |
|
51 |
findAnnotations(cf, Attribute.RuntimeVisibleTypeAnnotations, annos); |
|
52 |
findAnnotations(cf, Attribute.RuntimeInvisibleTypeAnnotations, annos); |
|
53 |
||
54 |
for (Field f : cf.fields) { |
|
55 |
findAnnotations(cf, f, annos); |
|
56 |
} |
|
57 |
for (Method m: cf.methods) { |
|
58 |
findAnnotations(cf, m, annos); |
|
59 |
} |
|
60 |
} |
|
61 |
||
62 |
private static void findAnnotations(ClassFile cf, Method m, List<TypeAnnotation> annos) { |
|
63 |
findAnnotations(cf, m, Attribute.RuntimeVisibleTypeAnnotations, annos); |
|
64 |
findAnnotations(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, annos); |
|
65 |
} |
|
66 |
||
67 |
private static void findAnnotations(ClassFile cf, Field m, List<TypeAnnotation> annos) { |
|
68 |
findAnnotations(cf, m, Attribute.RuntimeVisibleTypeAnnotations, annos); |
|
69 |
findAnnotations(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, annos); |
|
70 |
} |
|
71 |
||
72 |
// test the result of Attributes.getIndex according to expectations |
|
73 |
// encoded in the method's name |
|
74 |
private static void findAnnotations(ClassFile cf, String name, List<TypeAnnotation> annos) { |
|
75 |
int index = cf.attributes.getIndex(cf.constant_pool, name); |
|
76 |
if (index != -1) { |
|
77 |
Attribute attr = cf.attributes.get(index); |
|
78 |
assert attr instanceof RuntimeTypeAnnotations_attribute; |
|
79 |
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; |
|
80 |
annos.addAll(Arrays.asList(tAttr.annotations)); |
|
81 |
} |
|
82 |
} |
|
83 |
||
84 |
// test the result of Attributes.getIndex according to expectations |
|
85 |
// encoded in the method's name |
|
86 |
private static void findAnnotations(ClassFile cf, Method m, String name, List<TypeAnnotation> annos) { |
|
87 |
int index = m.attributes.getIndex(cf.constant_pool, name); |
|
88 |
if (index != -1) { |
|
89 |
Attribute attr = m.attributes.get(index); |
|
90 |
assert attr instanceof RuntimeTypeAnnotations_attribute; |
|
91 |
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; |
|
92 |
annos.addAll(Arrays.asList(tAttr.annotations)); |
|
93 |
} |
|
17578 | 94 |
|
95 |
int cindex = m.attributes.getIndex(cf.constant_pool, Attribute.Code); |
|
96 |
if (cindex != -1) { |
|
97 |
Attribute cattr = m.attributes.get(cindex); |
|
98 |
assert cattr instanceof Code_attribute; |
|
99 |
Code_attribute cAttr = (Code_attribute)cattr; |
|
100 |
index = cAttr.attributes.getIndex(cf.constant_pool, name); |
|
101 |
if (index != -1) { |
|
102 |
Attribute attr = cAttr.attributes.get(index); |
|
103 |
assert attr instanceof RuntimeTypeAnnotations_attribute; |
|
104 |
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; |
|
105 |
annos.addAll(Arrays.asList(tAttr.annotations)); |
|
106 |
} |
|
107 |
} |
|
15385 | 108 |
} |
109 |
||
110 |
// test the result of Attributes.getIndex according to expectations |
|
111 |
// encoded in the method's name |
|
112 |
private static void findAnnotations(ClassFile cf, Field m, String name, List<TypeAnnotation> annos) { |
|
113 |
int index = m.attributes.getIndex(cf.constant_pool, name); |
|
114 |
if (index != -1) { |
|
115 |
Attribute attr = m.attributes.get(index); |
|
116 |
assert attr instanceof RuntimeTypeAnnotations_attribute; |
|
117 |
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr; |
|
118 |
annos.addAll(Arrays.asList(tAttr.annotations)); |
|
119 |
} |
|
120 |
} |
|
121 |
||
122 |
/////////////////////// Equality testing ///////////////////// |
|
123 |
private static boolean areEquals(int a, int b) { |
|
124 |
return a == b || a == IGNORE_VALUE || b == IGNORE_VALUE; |
|
125 |
} |
|
126 |
||
127 |
private static boolean areEquals(int[] a, int[] a2) { |
|
128 |
if (a==a2) |
|
129 |
return true; |
|
130 |
if (a==null || a2==null) |
|
131 |
return false; |
|
132 |
||
133 |
int length = a.length; |
|
134 |
if (a2.length != length) |
|
135 |
return false; |
|
136 |
||
137 |
for (int i=0; i<length; i++) |
|
138 |
if (a[i] != a2[i] && a[i] != IGNORE_VALUE && a2[i] != IGNORE_VALUE) |
|
139 |
return false; |
|
140 |
||
141 |
return true; |
|
142 |
} |
|
143 |
||
144 |
public static boolean areEquals(TypeAnnotation.Position p1, TypeAnnotation.Position p2) { |
|
24896
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
145 |
return p1 == p2 || !(p1 == null || p2 == null) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
146 |
p1.type == p2.type && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
147 |
(p1.location.equals(p2.location)) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
148 |
areEquals(p1.offset, p2.offset) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
149 |
areEquals(p1.lvarOffset, p2.lvarOffset) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
150 |
areEquals(p1.lvarLength, p2.lvarLength) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
151 |
areEquals(p1.lvarIndex, p2.lvarIndex) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
152 |
areEquals(p1.bound_index, p2.bound_index) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
153 |
areEquals(p1.parameter_index, p2.parameter_index) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
154 |
areEquals(p1.type_index, p2.type_index) && |
986d876a9121
8042451: Write tests for all possible kinds of type annotation
aeremeev
parents:
17578
diff
changeset
|
155 |
areEquals(p1.exception_index, p2.exception_index); |
15385 | 156 |
|
157 |
} |
|
158 |
||
159 |
private static TypeAnnotation findAnnotation(String name, List<TypeAnnotation> annotations, ClassFile cf) throws InvalidIndex, UnexpectedEntry { |
|
160 |
String properName = "L" + name + ";"; |
|
161 |
for (TypeAnnotation anno : annotations) { |
|
162 |
String actualName = cf.constant_pool.getUTF8Value(anno.annotation.type_index); |
|
163 |
if (properName.equals(actualName)) |
|
164 |
return anno; |
|
165 |
} |
|
166 |
return null; |
|
167 |
} |
|
168 |
||
169 |
public static boolean compare(Map<String, TypeAnnotation.Position> expectedAnnos, |
|
170 |
List<TypeAnnotation> actualAnnos, ClassFile cf) throws InvalidIndex, UnexpectedEntry { |
|
171 |
if (actualAnnos.size() != expectedAnnos.size()) { |
|
172 |
throw new ComparisionException("Wrong number of annotations", |
|
173 |
expectedAnnos, |
|
174 |
actualAnnos); |
|
175 |
} |
|
176 |
||
177 |
for (Map.Entry<String, TypeAnnotation.Position> e : expectedAnnos.entrySet()) { |
|
178 |
String aName = e.getKey(); |
|
179 |
TypeAnnotation.Position expected = e.getValue(); |
|
180 |
TypeAnnotation actual = findAnnotation(aName, actualAnnos, cf); |
|
181 |
if (actual == null) |
|
182 |
throw new ComparisionException("Expected annotation not found: " + aName); |
|
183 |
||
184 |
if (!areEquals(expected, actual.position)) { |
|
185 |
throw new ComparisionException("Unexpected position for annotation : " + aName + |
|
186 |
"\n Expected: " + expected.toString() + |
|
187 |
"\n Found: " + actual.position.toString()); |
|
188 |
} |
|
189 |
} |
|
190 |
return true; |
|
191 |
} |
|
192 |
} |
|
193 |
||
194 |
class ComparisionException extends RuntimeException { |
|
195 |
private static final long serialVersionUID = -3930499712333815821L; |
|
196 |
||
197 |
public final Map<String, TypeAnnotation.Position> expected; |
|
198 |
public final List<TypeAnnotation> found; |
|
199 |
||
200 |
public ComparisionException(String message) { |
|
201 |
this(message, null, null); |
|
202 |
} |
|
203 |
||
204 |
public ComparisionException(String message, Map<String, TypeAnnotation.Position> expected, List<TypeAnnotation> found) { |
|
205 |
super(message); |
|
206 |
this.expected = expected; |
|
207 |
this.found = found; |
|
208 |
} |
|
209 |
||
210 |
public String toString() { |
|
211 |
String str = super.toString(); |
|
212 |
if (expected != null && found != null) { |
|
213 |
str += "\n\tExpected: " + expected.size() + " annotations; but found: " + found.size() + " annotations\n" + |
|
214 |
" Expected: " + expected + |
|
215 |
"\n Found: " + found; |
|
216 |
} |
|
217 |
return str; |
|
218 |
} |
|
219 |
} |