1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.generic;
18
19 import org.apache.bcel.Constants;
20 import org.apache.bcel.Repository;
21 import org.apache.bcel.classfile.JavaClass;
22
23 /***
24 * Super class for object and array types.
25 *
26 * @version $Id: ReferenceType.java 386056 2006-03-15 11:31:56Z tcurdt $
27 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
28 */
29 public abstract class ReferenceType extends Type {
30
31 protected ReferenceType(byte t, String s) {
32 super(t, s);
33 }
34
35
36 /*** Class is non-abstract but not instantiable from the outside
37 */
38 ReferenceType() {
39 super(Constants.T_OBJECT, "<null object>");
40 }
41
42
43 /***
44 * Return true iff this type is castable to another type t as defined in
45 * the JVM specification. The case where this is Type.NULL is not
46 * defined (see the CHECKCAST definition in the JVM specification).
47 * However, because e.g. CHECKCAST doesn't throw a
48 * ClassCastException when casting a null reference to any Object,
49 * true is returned in this case.
50 *
51 * @throws ClassNotFoundException if any classes or interfaces required
52 * to determine assignment compatibility can't be found
53 */
54 public boolean isCastableTo( Type t ) throws ClassNotFoundException {
55 if (this.equals(Type.NULL)) {
56 return true;
57 }
58 return isAssignmentCompatibleWith(t);
59
60
61
62 }
63
64
65 /***
66 * Return true iff this is assignment compatible with another type t
67 * as defined in the JVM specification; see the AASTORE definition
68 * there.
69 * @throws ClassNotFoundException if any classes or interfaces required
70 * to determine assignment compatibility can't be found
71 */
72 public boolean isAssignmentCompatibleWith( Type t ) throws ClassNotFoundException {
73 if (!(t instanceof ReferenceType)) {
74 return false;
75 }
76 ReferenceType T = (ReferenceType) t;
77 if (this.equals(Type.NULL)) {
78 return true;
79 }
80
81
82 if ((this instanceof ObjectType) && (((ObjectType) this).referencesClassExact())) {
83
84
85
86 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) {
87 if (this.equals(T)) {
88 return true;
89 }
90 if (Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T)
91 .getClassName())) {
92 return true;
93 }
94 }
95
96
97 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) {
98 if (Repository.implementationOf(((ObjectType) this).getClassName(),
99 ((ObjectType) T).getClassName())) {
100 return true;
101 }
102 }
103 }
104
105
106 if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterfaceExact())) {
107
108
109 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) {
110 if (T.equals(Type.OBJECT)) {
111 return true;
112 }
113 }
114
115
116
117 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) {
118 if (this.equals(T)) {
119 return true;
120 }
121 if (Repository.implementationOf(((ObjectType) this).getClassName(),
122 ((ObjectType) T).getClassName())) {
123 return true;
124 }
125 }
126 }
127
128
129
130 if (this instanceof ArrayType) {
131
132
133 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) {
134 if (T.equals(Type.OBJECT)) {
135 return true;
136 }
137 }
138
139
140
141 if (T instanceof ArrayType) {
142
143
144 Type sc = ((ArrayType) this).getElementType();
145 Type tc = ((ArrayType) T).getElementType();
146 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) {
147 return true;
148 }
149
150
151
152 if (tc instanceof ReferenceType && sc instanceof ReferenceType
153 && ((ReferenceType) sc).isAssignmentCompatibleWith(tc)) {
154 return true;
155 }
156 }
157
158
159
160
161
162
163 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) {
164 for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) {
165 if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) {
166 return true;
167 }
168 }
169 }
170 }
171 return false;
172 }
173
174
175 /***
176 * This commutative operation returns the first common superclass (narrowest ReferenceType
177 * referencing a class, not an interface).
178 * If one of the types is a superclass of the other, the former is returned.
179 * If "this" is Type.NULL, then t is returned.
180 * If t is Type.NULL, then "this" is returned.
181 * If "this" equals t ['this.equals(t)'] "this" is returned.
182 * If "this" or t is an ArrayType, then Type.OBJECT is returned;
183 * unless their dimensions match. Then an ArrayType of the same
184 * number of dimensions is returned, with its basic type being the
185 * first common super class of the basic types of "this" and t.
186 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned.
187 * If not all of the two classes' superclasses cannot be found, "null" is returned.
188 * See the JVM specification edition 2, "ß4.9.2 The Bytecode Verifier".
189 *
190 * @throws ClassNotFoundException on failure to find superclasses of this
191 * type, or the type passed as a parameter
192 */
193 public ReferenceType getFirstCommonSuperclass( ReferenceType t ) throws ClassNotFoundException {
194 if (this.equals(Type.NULL)) {
195 return t;
196 }
197 if (t.equals(Type.NULL)) {
198 return this;
199 }
200 if (this.equals(t)) {
201 return this;
202
203
204
205
206
207
208
209 }
210
211 if ((this instanceof ArrayType) && (t instanceof ArrayType)) {
212 ArrayType arrType1 = (ArrayType) this;
213 ArrayType arrType2 = (ArrayType) t;
214 if ((arrType1.getDimensions() == arrType2.getDimensions())
215 && arrType1.getBasicType() instanceof ObjectType
216 && arrType2.getBasicType() instanceof ObjectType) {
217 return new ArrayType(((ObjectType) arrType1.getBasicType())
218 .getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), arrType1
219 .getDimensions());
220 }
221 }
222 if ((this instanceof ArrayType) || (t instanceof ArrayType)) {
223 return Type.OBJECT;
224
225 }
226 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface())
227 || ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) {
228 return Type.OBJECT;
229
230
231
232 }
233
234 ObjectType thiz = (ObjectType) this;
235 ObjectType other = (ObjectType) t;
236 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName());
237 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName());
238 if ((thiz_sups == null) || (other_sups == null)) {
239 return null;
240 }
241
242 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1];
243 JavaClass[] t_sups = new JavaClass[other_sups.length + 1];
244 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length);
245 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length);
246 this_sups[0] = Repository.lookupClass(thiz.getClassName());
247 t_sups[0] = Repository.lookupClass(other.getClassName());
248 for (int i = 0; i < t_sups.length; i++) {
249 for (int j = 0; j < this_sups.length; j++) {
250 if (this_sups[j].equals(t_sups[i])) {
251 return new ObjectType(this_sups[j].getClassName());
252 }
253 }
254 }
255
256 return null;
257 }
258
259
260 /***
261 * This commutative operation returns the first common superclass (narrowest ReferenceType
262 * referencing a class, not an interface).
263 * If one of the types is a superclass of the other, the former is returned.
264 * If "this" is Type.NULL, then t is returned.
265 * If t is Type.NULL, then "this" is returned.
266 * If "this" equals t ['this.equals(t)'] "this" is returned.
267 * If "this" or t is an ArrayType, then Type.OBJECT is returned.
268 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned.
269 * If not all of the two classes' superclasses cannot be found, "null" is returned.
270 * See the JVM specification edition 2, "ß4.9.2 The Bytecode Verifier".
271 *
272 * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has
273 * slightly changed semantics.
274 * @throws ClassNotFoundException on failure to find superclasses of this
275 * type, or the type passed as a parameter
276 */
277 public ReferenceType firstCommonSuperclass( ReferenceType t ) throws ClassNotFoundException {
278 if (this.equals(Type.NULL)) {
279 return t;
280 }
281 if (t.equals(Type.NULL)) {
282 return this;
283 }
284 if (this.equals(t)) {
285 return this;
286
287
288
289
290
291
292
293 }
294 if ((this instanceof ArrayType) || (t instanceof ArrayType)) {
295 return Type.OBJECT;
296
297 }
298 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface())
299 || ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) {
300 return Type.OBJECT;
301
302
303
304 }
305
306 ObjectType thiz = (ObjectType) this;
307 ObjectType other = (ObjectType) t;
308 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName());
309 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName());
310 if ((thiz_sups == null) || (other_sups == null)) {
311 return null;
312 }
313
314 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1];
315 JavaClass[] t_sups = new JavaClass[other_sups.length + 1];
316 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length);
317 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length);
318 this_sups[0] = Repository.lookupClass(thiz.getClassName());
319 t_sups[0] = Repository.lookupClass(other.getClassName());
320 for (int i = 0; i < t_sups.length; i++) {
321 for (int j = 0; j < this_sups.length; j++) {
322 if (this_sups[j].equals(t_sups[i])) {
323 return new ObjectType(this_sups[j].getClassName());
324 }
325 }
326 }
327
328 return null;
329 }
330 }