18 * limitations under the License. |
18 * limitations under the License. |
19 */ |
19 */ |
20 |
20 |
21 package com.sun.org.apache.bcel.internal.generic; |
21 package com.sun.org.apache.bcel.internal.generic; |
22 |
22 |
23 |
23 import com.sun.org.apache.bcel.internal.Const; |
24 import com.sun.org.apache.bcel.internal.Constants; |
|
25 import com.sun.org.apache.bcel.internal.Repository; |
24 import com.sun.org.apache.bcel.internal.Repository; |
26 import com.sun.org.apache.bcel.internal.classfile.JavaClass; |
25 import com.sun.org.apache.bcel.internal.classfile.JavaClass; |
27 |
26 |
28 /** |
27 /** |
29 * Super class for object and array types. |
28 * Super class for object and array types. |
30 * |
29 * |
31 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> |
30 * @version $Id: ReferenceType.java 1749603 2016-06-21 20:50:19Z ggregory $ |
32 */ |
31 */ |
33 public abstract class ReferenceType extends Type { |
32 public abstract class ReferenceType extends Type { |
34 protected ReferenceType(byte t, String s) { |
33 |
35 super(t, s); |
34 protected ReferenceType(final byte t, final String s) { |
36 } |
35 super(t, s); |
37 |
36 } |
38 /** Class is non-abstract but not instantiable from the outside |
37 |
39 */ |
38 |
40 ReferenceType() { |
39 /** Class is non-abstract but not instantiable from the outside |
41 super(Constants.T_OBJECT, "<null object>"); |
40 */ |
42 } |
41 ReferenceType() { |
43 |
42 super(Const.T_OBJECT, "<null object>"); |
44 /** |
43 } |
45 * Return true iff this type is castable to another type t as defined in |
44 |
46 * the JVM specification. The case where this is Type.NULL is not |
45 |
47 * defined (see the CHECKCAST definition in the JVM specification). |
46 /** |
48 * However, because e.g. CHECKCAST doesn't throw a |
47 * Return true iff this type is castable to another type t as defined in |
49 * ClassCastException when casting a null reference to any Object, |
48 * the JVM specification. The case where this is Type.NULL is not |
50 * true is returned in this case. |
49 * defined (see the CHECKCAST definition in the JVM specification). |
51 */ |
50 * However, because e.g. CHECKCAST doesn't throw a |
52 public boolean isCastableTo(Type t) { |
51 * ClassCastException when casting a null reference to any Object, |
53 if (this.equals(Type.NULL)) |
52 * true is returned in this case. |
54 return true; // If this is ever changed in isAssignmentCompatible() |
53 * |
55 |
54 * @throws ClassNotFoundException if any classes or interfaces required |
56 return isAssignmentCompatibleWith(t); |
55 * to determine assignment compatibility can't be found |
57 /* Yes, it's true: It's the same definition. |
56 */ |
58 * See vmspec2 AASTORE / CHECKCAST definitions. |
57 public boolean isCastableTo( final Type t ) throws ClassNotFoundException { |
59 */ |
58 if (this.equals(Type.NULL)) { |
60 } |
59 return t instanceof ReferenceType; // If this is ever changed in isAssignmentCompatible() |
61 |
60 } |
62 /** |
61 return isAssignmentCompatibleWith(t); |
63 * Return true iff this is assignment compatible with another type t |
62 /* Yes, it's true: It's the same definition. |
64 * as defined in the JVM specification; see the AASTORE definition |
63 * See vmspec2 AASTORE / CHECKCAST definitions. |
65 * there. |
|
66 */ |
|
67 public boolean isAssignmentCompatibleWith(Type t) { |
|
68 if (!(t instanceof ReferenceType)) |
|
69 return false; |
|
70 |
|
71 ReferenceType T = (ReferenceType) t; |
|
72 |
|
73 if (this.equals(Type.NULL)) |
|
74 return true; // This is not explicitely stated, but clear. Isn't it? |
|
75 |
|
76 /* If this is a class type then |
|
77 */ |
|
78 if ((this instanceof ObjectType) && (((ObjectType) this).referencesClass())) { |
|
79 /* If T is a class type, then this must be the same class as T, |
|
80 or this must be a subclass of T; |
|
81 */ |
|
82 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { |
|
83 if (this.equals(T)) |
|
84 return true; |
|
85 |
|
86 if (Repository.instanceOf(((ObjectType) this).getClassName(), |
|
87 ((ObjectType) T).getClassName())) |
|
88 return true; |
|
89 } |
|
90 |
|
91 /* If T is an interface type, this must implement interface T. |
|
92 */ |
|
93 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { |
|
94 if (Repository.implementationOf(((ObjectType) this).getClassName(), |
|
95 ((ObjectType) T).getClassName())) |
|
96 return true; |
|
97 } |
|
98 } |
|
99 |
|
100 /* If this is an interface type, then: |
|
101 */ |
|
102 if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterface())) { |
|
103 /* If T is a class type, then T must be Object (2.4.7). |
|
104 */ |
|
105 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { |
|
106 if (T.equals(Type.OBJECT)) return true; |
|
107 } |
|
108 |
|
109 /* If T is an interface type, then T must be the same interface |
|
110 * as this or a superinterface of this (2.13.2). |
|
111 */ |
|
112 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { |
|
113 if (this.equals(T)) return true; |
|
114 if (Repository.implementationOf(((ObjectType) this).getClassName(), |
|
115 ((ObjectType) T).getClassName())) |
|
116 return true; |
|
117 } |
|
118 } |
|
119 |
|
120 /* If this is an array type, namely, the type SC[], that is, an |
|
121 * array of components of type SC, then: |
|
122 */ |
|
123 if (this instanceof ArrayType) { |
|
124 /* If T is a class type, then T must be Object (2.4.7). |
|
125 */ |
|
126 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) { |
|
127 if (T.equals(Type.OBJECT)) return true; |
|
128 } |
|
129 |
|
130 /* If T is an array type TC[], that is, an array of components |
|
131 * of type TC, then one of the following must be true: |
|
132 */ |
|
133 if (T instanceof ArrayType) { |
|
134 /* TC and SC are the same primitive type (2.4.1). |
|
135 */ |
64 */ |
136 Type sc = ((ArrayType) this).getElementType(); |
65 } |
137 Type tc = ((ArrayType) this).getElementType(); |
66 |
138 |
67 |
139 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) |
68 /** |
140 return true; |
69 * Return true iff this is assignment compatible with another type t |
141 |
70 * as defined in the JVM specification; see the AASTORE definition |
142 /* TC and SC are reference types (2.4.6), and type SC is |
71 * there. |
143 * assignable to TC by these runtime rules. |
72 * @throws ClassNotFoundException if any classes or interfaces required |
|
73 * to determine assignment compatibility can't be found |
|
74 */ |
|
75 public boolean isAssignmentCompatibleWith( final Type t ) throws ClassNotFoundException { |
|
76 if (!(t instanceof ReferenceType)) { |
|
77 return false; |
|
78 } |
|
79 final ReferenceType T = (ReferenceType) t; |
|
80 if (this.equals(Type.NULL)) { |
|
81 return true; // This is not explicitely stated, but clear. Isn't it? |
|
82 } |
|
83 /* If this is a class type then |
144 */ |
84 */ |
145 if (tc instanceof ReferenceType && sc instanceof ReferenceType && |
85 if ((this instanceof ObjectType) && (((ObjectType) this).referencesClassExact())) { |
146 ((ReferenceType) sc).isAssignmentCompatibleWith((ReferenceType) tc)) |
86 /* If T is a class type, then this must be the same class as T, |
147 return true; |
87 or this must be a subclass of T; |
148 } |
88 */ |
149 |
89 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) { |
150 /* If T is an interface type, T must be one of the interfaces implemented by arrays (2.15). */ |
90 if (this.equals(T)) { |
151 // TODO: Check if this is still valid or find a way to dynamically find out which |
91 return true; |
152 // interfaces arrays implement. However, as of the JVM specification edition 2, there |
92 } |
153 // are at least two different pages where assignment compatibility is defined and |
93 if (Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T) |
154 // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or |
94 .getClassName())) { |
155 // 'java.io.Serializable'" |
95 return true; |
156 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) { |
96 } |
157 for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) { |
97 } |
158 if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) return true; |
98 /* If T is an interface type, this must implement interface T. |
159 } |
99 */ |
160 } |
100 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) { |
161 } |
101 if (Repository.implementationOf(((ObjectType) this).getClassName(), |
162 return false; // default. |
102 ((ObjectType) T).getClassName())) { |
163 } |
103 return true; |
164 |
104 } |
165 /** |
105 } |
166 * This commutative operation returns the first common superclass (narrowest ReferenceType |
106 } |
167 * referencing a class, not an interface). |
107 /* If this is an interface type, then: |
168 * If one of the types is a superclass of the other, the former is returned. |
108 */ |
169 * If "this" is Type.NULL, then t is returned. |
109 if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterfaceExact())) { |
170 * If t is Type.NULL, then "this" is returned. |
110 /* If T is a class type, then T must be Object (2.4.7). |
171 * If "this" equals t ['this.equals(t)'] "this" is returned. |
111 */ |
172 * If "this" or t is an ArrayType, then Type.OBJECT is returned; |
112 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) { |
173 * unless their dimensions match. Then an ArrayType of the same |
113 if (T.equals(Type.OBJECT)) { |
174 * number of dimensions is returned, with its basic type being the |
114 return true; |
175 * first common super class of the basic types of "this" and t. |
115 } |
176 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. |
116 } |
177 * If not all of the two classes' superclasses cannot be found, "null" is returned. |
117 /* If T is an interface type, then T must be the same interface |
178 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". |
118 * as this or a superinterface of this (2.13.2). |
179 */ |
119 */ |
180 public ReferenceType getFirstCommonSuperclass(ReferenceType t) { |
120 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) { |
181 if (this.equals(Type.NULL)) return t; |
121 if (this.equals(T)) { |
182 if (t.equals(Type.NULL)) return this; |
122 return true; |
183 if (this.equals(t)) return this; |
123 } |
184 /* |
124 if (Repository.implementationOf(((ObjectType) this).getClassName(), |
185 * TODO: Above sounds a little arbitrary. On the other hand, there is |
125 ((ObjectType) T).getClassName())) { |
186 * no object referenced by Type.NULL so we can also say all the objects |
126 return true; |
187 * referenced by Type.NULL were derived from java.lang.Object. |
127 } |
188 * However, the Java Language's "instanceof" operator proves us wrong: |
128 } |
189 * "null" is not referring to an instance of java.lang.Object :) |
129 } |
190 */ |
130 /* If this is an array type, namely, the type SC[], that is, an |
191 |
131 * array of components of type SC, then: |
192 /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */ |
132 */ |
193 |
133 if (this instanceof ArrayType) { |
194 if ((this instanceof ArrayType) && (t instanceof ArrayType)) { |
134 /* If T is a class type, then T must be Object (2.4.7). |
195 ArrayType arrType1 = (ArrayType) this; |
135 */ |
196 ArrayType arrType2 = (ArrayType) t; |
136 if ((T instanceof ObjectType) && (((ObjectType) T).referencesClassExact())) { |
197 if ( |
137 if (T.equals(Type.OBJECT)) { |
198 (arrType1.getDimensions() == arrType2.getDimensions()) && |
138 return true; |
199 arrType1.getBasicType() instanceof ObjectType && |
139 } |
200 arrType2.getBasicType() instanceof ObjectType) { |
140 } |
201 return new ArrayType( |
141 /* If T is an array type TC[], that is, an array of components |
202 ((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), |
142 * of type TC, then one of the following must be true: |
203 arrType1.getDimensions() |
143 */ |
204 ); |
144 if (T instanceof ArrayType) { |
205 |
145 /* TC and SC are the same primitive type (2.4.1). |
206 } |
146 */ |
207 } |
147 final Type sc = ((ArrayType) this).getElementType(); |
208 |
148 final Type tc = ((ArrayType) T).getElementType(); |
209 if ((this instanceof ArrayType) || (t instanceof ArrayType)) |
149 if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc)) { |
210 return Type.OBJECT; |
150 return true; |
211 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? |
151 } |
212 |
152 /* TC and SC are reference types (2.4.6), and type SC is |
213 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || |
153 * assignable to TC by these runtime rules. |
214 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) |
154 */ |
215 return Type.OBJECT; |
155 if (tc instanceof ReferenceType && sc instanceof ReferenceType |
216 // TODO: The above line is correct comparing to the vmspec2. But one could |
156 && ((ReferenceType) sc).isAssignmentCompatibleWith(tc)) { |
217 // make class file verification a bit stronger here by using the notion of |
157 return true; |
218 // superinterfaces or even castability or assignment compatibility. |
158 } |
219 |
159 } |
220 |
160 /* If T is an interface type, T must be one of the interfaces implemented by arrays (2.15). */ |
221 // this and t are ObjectTypes, see above. |
161 // TODO: Check if this is still valid or find a way to dynamically find out which |
222 ObjectType thiz = (ObjectType) this; |
162 // interfaces arrays implement. However, as of the JVM specification edition 2, there |
223 ObjectType other = (ObjectType) t; |
163 // are at least two different pages where assignment compatibility is defined and |
224 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); |
164 // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or |
225 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); |
165 // 'java.io.Serializable'" |
226 |
166 if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterfaceExact())) { |
227 if ((thiz_sups == null) || (other_sups == null)) { |
167 for (final String element : Const.getInterfacesImplementedByArrays()) { |
228 return null; |
168 if (T.equals(ObjectType.getInstance(element))) { |
229 } |
169 return true; |
230 |
170 } |
231 // Waaahh... |
171 } |
232 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; |
172 } |
233 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; |
173 } |
234 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); |
174 return false; // default. |
235 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); |
175 } |
236 this_sups[0] = Repository.lookupClass(thiz.getClassName()); |
176 |
237 t_sups[0] = Repository.lookupClass(other.getClassName()); |
177 |
238 |
178 /** |
239 for (int i = 0; i < t_sups.length; i++) { |
179 * This commutative operation returns the first common superclass (narrowest ReferenceType |
240 for (int j = 0; j < this_sups.length; j++) { |
180 * referencing a class, not an interface). |
241 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); |
181 * If one of the types is a superclass of the other, the former is returned. |
242 } |
182 * If "this" is Type.NULL, then t is returned. |
243 } |
183 * If t is Type.NULL, then "this" is returned. |
244 |
184 * If "this" equals t ['this.equals(t)'] "this" is returned. |
245 // Huh? Did you ask for Type.OBJECT's superclass?? |
185 * If "this" or t is an ArrayType, then Type.OBJECT is returned; |
246 return null; |
186 * unless their dimensions match. Then an ArrayType of the same |
247 } |
187 * number of dimensions is returned, with its basic type being the |
248 |
188 * first common super class of the basic types of "this" and t. |
249 /** |
189 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. |
250 * This commutative operation returns the first common superclass (narrowest ReferenceType |
190 * If not all of the two classes' superclasses cannot be found, "null" is returned. |
251 * referencing a class, not an interface). |
191 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". |
252 * If one of the types is a superclass of the other, the former is returned. |
192 * |
253 * If "this" is Type.NULL, then t is returned. |
193 * @throws ClassNotFoundException on failure to find superclasses of this |
254 * If t is Type.NULL, then "this" is returned. |
194 * type, or the type passed as a parameter |
255 * If "this" equals t ['this.equals(t)'] "this" is returned. |
195 */ |
256 * If "this" or t is an ArrayType, then Type.OBJECT is returned. |
196 public ReferenceType getFirstCommonSuperclass( final ReferenceType t ) throws ClassNotFoundException { |
257 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. |
197 if (this.equals(Type.NULL)) { |
258 * If not all of the two classes' superclasses cannot be found, "null" is returned. |
198 return t; |
259 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". |
199 } |
260 * |
200 if (t.equals(Type.NULL)) { |
261 * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has |
201 return this; |
262 * slightly changed semantics. |
202 } |
263 */ |
203 if (this.equals(t)) { |
264 @Deprecated |
204 return this; |
265 public ReferenceType firstCommonSuperclass(ReferenceType t) { |
205 /* |
266 if (this.equals(Type.NULL)) return t; |
206 * TODO: Above sounds a little arbitrary. On the other hand, there is |
267 if (t.equals(Type.NULL)) return this; |
207 * no object referenced by Type.NULL so we can also say all the objects |
268 if (this.equals(t)) return this; |
208 * referenced by Type.NULL were derived from java.lang.Object. |
269 /* |
209 * However, the Java Language's "instanceof" operator proves us wrong: |
270 * TODO: Above sounds a little arbitrary. On the other hand, there is |
210 * "null" is not referring to an instance of java.lang.Object :) |
271 * no object referenced by Type.NULL so we can also say all the objects |
211 */ |
272 * referenced by Type.NULL were derived from java.lang.Object. |
212 } |
273 * However, the Java Language's "instanceof" operator proves us wrong: |
213 /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */ |
274 * "null" is not referring to an instance of java.lang.Object :) |
214 if ((this instanceof ArrayType) && (t instanceof ArrayType)) { |
275 */ |
215 final ArrayType arrType1 = (ArrayType) this; |
276 |
216 final ArrayType arrType2 = (ArrayType) t; |
277 if ((this instanceof ArrayType) || (t instanceof ArrayType)) |
217 if ((arrType1.getDimensions() == arrType2.getDimensions()) |
278 return Type.OBJECT; |
218 && arrType1.getBasicType() instanceof ObjectType |
279 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? |
219 && arrType2.getBasicType() instanceof ObjectType) { |
280 |
220 return new ArrayType(((ObjectType) arrType1.getBasicType()) |
281 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) || |
221 .getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()), arrType1 |
282 ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) |
222 .getDimensions()); |
283 return Type.OBJECT; |
223 } |
284 // TODO: The above line is correct comparing to the vmspec2. But one could |
224 } |
285 // make class file verification a bit stronger here by using the notion of |
225 if ((this instanceof ArrayType) || (t instanceof ArrayType)) { |
286 // superinterfaces or even castability or assignment compatibility. |
226 return Type.OBJECT; |
287 |
227 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? |
288 |
228 } |
289 // this and t are ObjectTypes, see above. |
229 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterfaceExact()) |
290 ObjectType thiz = (ObjectType) this; |
230 || ((t instanceof ObjectType) && ((ObjectType) t).referencesInterfaceExact())) { |
291 ObjectType other = (ObjectType) t; |
231 return Type.OBJECT; |
292 JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); |
232 // TODO: The above line is correct comparing to the vmspec2. But one could |
293 JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); |
233 // make class file verification a bit stronger here by using the notion of |
294 |
234 // superinterfaces or even castability or assignment compatibility. |
295 if ((thiz_sups == null) || (other_sups == null)) { |
235 } |
296 return null; |
236 // this and t are ObjectTypes, see above. |
297 } |
237 final ObjectType thiz = (ObjectType) this; |
298 |
238 final ObjectType other = (ObjectType) t; |
299 // Waaahh... |
239 final JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); |
300 JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; |
240 final JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); |
301 JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; |
241 if ((thiz_sups == null) || (other_sups == null)) { |
302 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); |
242 return null; |
303 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); |
243 } |
304 this_sups[0] = Repository.lookupClass(thiz.getClassName()); |
244 // Waaahh... |
305 t_sups[0] = Repository.lookupClass(other.getClassName()); |
245 final JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; |
306 |
246 final JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; |
307 for (int i = 0; i < t_sups.length; i++) { |
247 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); |
308 for (int j = 0; j < this_sups.length; j++) { |
248 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); |
309 if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName()); |
249 this_sups[0] = Repository.lookupClass(thiz.getClassName()); |
310 } |
250 t_sups[0] = Repository.lookupClass(other.getClassName()); |
311 } |
251 for (final JavaClass t_sup : t_sups) { |
312 |
252 for (final JavaClass this_sup : this_sups) { |
313 // Huh? Did you ask for Type.OBJECT's superclass?? |
253 if (this_sup.equals(t_sup)) { |
314 return null; |
254 return ObjectType.getInstance(this_sup.getClassName()); |
315 } |
255 } |
|
256 } |
|
257 } |
|
258 // Huh? Did you ask for Type.OBJECT's superclass?? |
|
259 return null; |
|
260 } |
|
261 |
|
262 /** |
|
263 * This commutative operation returns the first common superclass (narrowest ReferenceType |
|
264 * referencing a class, not an interface). |
|
265 * If one of the types is a superclass of the other, the former is returned. |
|
266 * If "this" is Type.NULL, then t is returned. |
|
267 * If t is Type.NULL, then "this" is returned. |
|
268 * If "this" equals t ['this.equals(t)'] "this" is returned. |
|
269 * If "this" or t is an ArrayType, then Type.OBJECT is returned. |
|
270 * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. |
|
271 * If not all of the two classes' superclasses cannot be found, "null" is returned. |
|
272 * See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". |
|
273 * |
|
274 * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has |
|
275 * slightly changed semantics. |
|
276 * @throws ClassNotFoundException on failure to find superclasses of this |
|
277 * type, or the type passed as a parameter |
|
278 */ |
|
279 @Deprecated |
|
280 public ReferenceType firstCommonSuperclass( final ReferenceType t ) throws ClassNotFoundException { |
|
281 if (this.equals(Type.NULL)) { |
|
282 return t; |
|
283 } |
|
284 if (t.equals(Type.NULL)) { |
|
285 return this; |
|
286 } |
|
287 if (this.equals(t)) { |
|
288 return this; |
|
289 /* |
|
290 * TODO: Above sounds a little arbitrary. On the other hand, there is |
|
291 * no object referenced by Type.NULL so we can also say all the objects |
|
292 * referenced by Type.NULL were derived from java.lang.Object. |
|
293 * However, the Java Language's "instanceof" operator proves us wrong: |
|
294 * "null" is not referring to an instance of java.lang.Object :) |
|
295 */ |
|
296 } |
|
297 if ((this instanceof ArrayType) || (t instanceof ArrayType)) { |
|
298 return Type.OBJECT; |
|
299 // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? |
|
300 } |
|
301 if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) |
|
302 || ((t instanceof ObjectType) && ((ObjectType) t).referencesInterface())) { |
|
303 return Type.OBJECT; |
|
304 // TODO: The above line is correct comparing to the vmspec2. But one could |
|
305 // make class file verification a bit stronger here by using the notion of |
|
306 // superinterfaces or even castability or assignment compatibility. |
|
307 } |
|
308 // this and t are ObjectTypes, see above. |
|
309 final ObjectType thiz = (ObjectType) this; |
|
310 final ObjectType other = (ObjectType) t; |
|
311 final JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName()); |
|
312 final JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName()); |
|
313 if ((thiz_sups == null) || (other_sups == null)) { |
|
314 return null; |
|
315 } |
|
316 // Waaahh... |
|
317 final JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1]; |
|
318 final JavaClass[] t_sups = new JavaClass[other_sups.length + 1]; |
|
319 System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length); |
|
320 System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length); |
|
321 this_sups[0] = Repository.lookupClass(thiz.getClassName()); |
|
322 t_sups[0] = Repository.lookupClass(other.getClassName()); |
|
323 for (final JavaClass t_sup : t_sups) { |
|
324 for (final JavaClass this_sup : this_sups) { |
|
325 if (this_sup.equals(t_sup)) { |
|
326 return ObjectType.getInstance(this_sup.getClassName()); |
|
327 } |
|
328 } |
|
329 } |
|
330 // Huh? Did you ask for Type.OBJECT's superclass?? |
|
331 return null; |
|
332 } |
316 } |
333 } |