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