    View Javadoc
    1   package org.apache.bcel.generic;
    2
    3   /* ====================================================================
    4    * The Apache Software License, Version 1.1
    5    *
    6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
    7    * reserved.
    8    *
    9    * Redistribution and use in source and binary forms, with or without
    10   * modification, are permitted provided that the following conditions
    11   * are met:
    12   *
    13   * 1. Redistributions of source code must retain the above copyright
    14   *    notice, this list of conditions and the following disclaimer.
    15   *
    16   * 2. Redistributions in binary form must reproduce the above copyright
    17   *    notice, this list of conditions and the following disclaimer in
    18   *    the documentation and/or other materials provided with the
    19   *    distribution.
    20   *
    21   * 3. The end-user documentation included with the redistribution,
    22   *    if any, must include the following acknowledgment:
    23   *       "This product includes software developed by the
    24   *        Apache Software Foundation (http://www.apache.org/)."
    25   *    Alternately, this acknowledgment may appear in the software itself,
    26   *    if and wherever such third-party acknowledgments normally appear.
    27   *
    28   * 4. The names "Apache" and "Apache Software Foundation" and
    29   *    "Apache BCEL" must not be used to endorse or promote products
    30   *    derived from this software without prior written permission. For
    31   *    written permission, please contact apache@apache.org.
    32   *
    33   * 5. Products derived from this software may not be called "Apache",
    34   *    "Apache BCEL", nor may "Apache" appear in their name, without
    35   *    prior written permission of the Apache Software Foundation.
    36   *
    37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
    41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    48   * SUCH DAMAGE.
    49   * ====================================================================
    50   *
    51   * This software consists of voluntary contributions made by many
    52   * individuals on behalf of the Apache Software Foundation.  For more
    53   * information on the Apache Software Foundation, please see
    54   * <http://www.apache.org/>;.
    55   */
    56
    57  import org.apache.bcel.Constants;
    58  import org.apache.bcel.Repository;
    59  import org.apache.bcel.classfile.JavaClass;
    60
    61  /***
    62   * Super class for object and array types.
    63   *
    64   * @version $Id: ReferenceType.java,v 1.5 2002/08/07 18:01:32 mdahm Exp $
    65   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
    66   */
    67  public abstract class ReferenceType extends Type {
    68    protected ReferenceType(byte t, String s) {
    69      super(t, s);
    70    }
    71
    72    /*** Class is non-abstract but not instantiable from the outside
    73     */
    74    ReferenceType() {
    75      super(Constants.T_OBJECT, "<null object>");
    76    }
    77
    78    /***
    79     * Return true iff this type is castable to another type t as defined in
    80     * the JVM specification.  The case where this is Type.NULL is not
    81     * defined (see the CHECKCAST definition in the JVM specification).
    82     * However, because e.g. CHECKCAST doesn't throw a
    83     * ClassCastException when casting a null reference to any Object,
    84     * true is returned in this case.
    85     */
    86    public boolean isCastableTo(Type t) {
    87      if (this.equals(Type.NULL))
    88        return true;		// If this is ever changed in isAssignmentCompatible()
    89
    90      return isAssignmentCompatibleWith(t);
    91      /* Yes, it's true: It's the same definition.
    92       * See vmspec2 AASTORE / CHECKCAST definitions.
    93       */
    94    }
    95
    96    /***
    97     * Return true iff this is assignment compatible with another type t
    98     * as defined in the JVM specification; see the AASTORE definition
    99     * there.
    100    */
    101   public boolean isAssignmentCompatibleWith(Type t) {
    102     if (!(t instanceof ReferenceType))
    103       return false;
    104
    105     ReferenceType T = (ReferenceType) t;
    106
    107     if (this.equals(Type.NULL))
    108       return true; // This is not explicitely stated, but clear. Isn't it?
    109
    110     /* If this is a class type then
    111      */
    112     if ((this instanceof ObjectType) && (((ObjectType) this).referencesClass())) {
    113       /* If T is a class type, then this must be the same class as T,
    114 	 or this must be a subclass of T;
    115       */
    116       if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) {
    117 	if (this.equals(T))
    118 	  return true;
    119
    120 	if (Repository.instanceOf(((ObjectType) this).getClassName(),
    121 				  ((ObjectType) T).getClassName()))
    122 	  return true;
    123       }
    124
    125       /* If T is an interface type, this must implement interface T.
    126        */
    127       if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) {
    128 	if (Repository.implementationOf(((ObjectType) this).getClassName(),
    129 					((ObjectType) T).getClassName()))
    130 	  return true;
    131       }
    132     }
    133
    134     /* If this is an interface type, then:
    135      */
    136     if ((this instanceof ObjectType) && (((ObjectType) this).referencesInterface())) {
    137       /* If T is a class type, then T must be Object (§2.4.7).
    138        */
    139       if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) {
    140 	if (T.equals(Type.OBJECT)) return true;
    141       }
    142
    143       /* If T is an interface type, then T must be the same interface
    144        * as this or a superinterface of this (§2.13.2).
    145        */
    146       if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) {
    147 	if (this.equals(T)) return true;
    148 	if (Repository.implementationOf(((ObjectType) this).getClassName(),
    149 					((ObjectType) T).getClassName()))
    150 	  return true;
    151       }
    152     }
    153
    154     /* If this is an array type, namely, the type SC[], that is, an
    155      * array of components of type SC, then:
    156      */
    157     if (this instanceof ArrayType) {
    158       /* If T is a class type, then T must be Object (§2.4.7).
    159        */
    160       if ((T instanceof ObjectType) && (((ObjectType) T).referencesClass())) {
    161 	if (T.equals(Type.OBJECT)) return true;
    162       }
    163
    164       /* If T is an array type TC[], that is, an array of components
    165        * of type TC, then one of the following must be true:
    166        */
    167       if (T instanceof ArrayType) {
    168 	/* TC and SC are the same primitive type (§2.4.1).
    169 	 */
    170 	Type sc = ((ArrayType) this).getElementType();
    171 	Type tc = ((ArrayType) this).getElementType();
    172
    173 	if (sc instanceof BasicType && tc instanceof BasicType && sc.equals(tc))
    174 	  return true;
    175
    176 	/* TC and SC are reference types (§2.4.6), and type SC is
    177 	 * assignable to TC by these runtime rules.
    178 	 */
    179 	if (tc instanceof ReferenceType && sc instanceof ReferenceType &&
    180 	    ((ReferenceType) sc).isAssignmentCompatibleWith((ReferenceType) tc))
    181 	  return true;
    182       }
    183
    184       /* If T is an interface type, T must be one of the interfaces implemented by arrays (§2.15). */
    185       // TODO: Check if this is still valid or find a way to dynamically find out which
    186       // interfaces arrays implement. However, as of the JVM specification edition 2, there
    187       // are at least two different pages where assignment compatibility is defined and
    188       // on one of them "interfaces implemented by arrays" is exchanged with "'Cloneable' or
    189       // 'java.io.Serializable'"
    190       if ((T instanceof ObjectType) && (((ObjectType) T).referencesInterface())) {
    191 	for (int ii = 0; ii < Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS.length; ii++) {
    192 	  if (T.equals(new ObjectType(Constants.INTERFACES_IMPLEMENTED_BY_ARRAYS[ii]))) return true;
    193 	}
    194       }
    195     }
    196     return false; // default.
    197   }
    198
    199   /***
    200    * This commutative operation returns the first common superclass (narrowest ReferenceType
    201    * referencing a class, not an interface).
    202    * If one of the types is a superclass of the other, the former is returned.
    203    * If "this" is Type.NULL, then t is returned.
    204    * If t is Type.NULL, then "this" is returned.
    205    * If "this" equals t ['this.equals(t)'] "this" is returned.
    206    * If "this" or t is an ArrayType, then Type.OBJECT is returned;
    207    * unless their dimensions match. Then an ArrayType of the same
    208    * number of dimensions is returned, with its basic type being the
    209    * first common super class of the basic types of "this" and t.
    210    * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned.
    211    * If not all of the two classes' superclasses cannot be found, "null" is returned.
    212    * See the JVM specification edition 2, "§4.9.2 The Bytecode Verifier".
    213    */
    214   public ReferenceType getFirstCommonSuperclass(ReferenceType t) {
    215     if (this.equals(Type.NULL)) return t;
    216     if (t.equals(Type.NULL)) return this;
    217     if (this.equals(t)) return this;
    218     /*
    219      * TODO: Above sounds a little arbitrary. On the other hand, there is
    220      * no object referenced by Type.NULL so we can also say all the objects
    221      * referenced by Type.NULL were derived from java.lang.Object.
    222      * However, the Java Language's "instanceof" operator proves us wrong:
    223      * "null" is not referring to an instance of java.lang.Object :)
    224      */
    225
    226     /* This code is from a bug report by Konstantin Shagin <konst@cs.technion.ac.il> */
    227
    228     if ((this instanceof ArrayType) && (t instanceof ArrayType)) {
    229       ArrayType arrType1 = (ArrayType) this;
    230       ArrayType arrType2 = (ArrayType) t;
    231       if (
    232 	  (arrType1.getDimensions() == arrType2.getDimensions()) &&
    233 	  arrType1.getBasicType() instanceof ObjectType &&
    234 	  arrType2.getBasicType() instanceof ObjectType) {
    235 	return new ArrayType(
    236 			     ((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()),
    237 			     arrType1.getDimensions()
    238 			     );
    239
    240       }
    241     }
    242
    243     if ((this instanceof ArrayType) || (t instanceof ArrayType))
    244       return Type.OBJECT;
    245     // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType?
    246
    247     if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) ||
    248 	((t instanceof ObjectType) && ((ObjectType) t).referencesInterface()))
    249       return Type.OBJECT;
    250     // TODO: The above line is correct comparing to the vmspec2. But one could
    251     // make class file verification a bit stronger here by using the notion of
    252     // superinterfaces or even castability or assignment compatibility.
    253
    254
    255     // this and t are ObjectTypes, see above.
    256     ObjectType thiz = (ObjectType) this;
    257     ObjectType other = (ObjectType) t;
    258     JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName());
    259     JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName());
    260
    261     if ((thiz_sups == null) || (other_sups == null)) {
    262       return null;
    263     }
    264
    265     // Waaahh...
    266     JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1];
    267     JavaClass[] t_sups = new JavaClass[other_sups.length + 1];
    268     System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length);
    269     System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length);
    270     this_sups[0] = Repository.lookupClass(thiz.getClassName());
    271     t_sups[0] = Repository.lookupClass(other.getClassName());
    272
    273     for (int i = 0; i < t_sups.length; i++) {
    274       for (int j = 0; j < this_sups.length; j++) {
    275 	if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName());
    276       }
    277     }
    278
    279     // Huh? Did you ask for Type.OBJECT's superclass??
    280     return null;
    281   }
    282
    283   /***
    284    * This commutative operation returns the first common superclass (narrowest ReferenceType
    285    * referencing a class, not an interface).
    286    * If one of the types is a superclass of the other, the former is returned.
    287    * If "this" is Type.NULL, then t is returned.
    288    * If t is Type.NULL, then "this" is returned.
    289    * If "this" equals t ['this.equals(t)'] "this" is returned.
    290    * If "this" or t is an ArrayType, then Type.OBJECT is returned.
    291    * If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned.
    292    * If not all of the two classes' superclasses cannot be found, "null" is returned.
    293    * See the JVM specification edition 2, "§4.9.2 The Bytecode Verifier".
    294    *
    295    * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has
    296    *             slightly changed semantics.
    297    */
    298   public ReferenceType firstCommonSuperclass(ReferenceType t) {
    299     if (this.equals(Type.NULL)) return t;
    300     if (t.equals(Type.NULL)) return this;
    301     if (this.equals(t)) return this;
    302     /*
    303      * TODO: Above sounds a little arbitrary. On the other hand, there is
    304      * no object referenced by Type.NULL so we can also say all the objects
    305      * referenced by Type.NULL were derived from java.lang.Object.
    306      * However, the Java Language's "instanceof" operator proves us wrong:
    307      * "null" is not referring to an instance of java.lang.Object :)
    308      */
    309
    310     if ((this instanceof ArrayType) || (t instanceof ArrayType))
    311       return Type.OBJECT;
    312     // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType?
    313
    314     if (((this instanceof ObjectType) && ((ObjectType) this).referencesInterface()) ||
    315 	((t instanceof ObjectType) && ((ObjectType) t).referencesInterface()))
    316       return Type.OBJECT;
    317     // TODO: The above line is correct comparing to the vmspec2. But one could
    318     // make class file verification a bit stronger here by using the notion of
    319     // superinterfaces or even castability or assignment compatibility.
    320
    321
    322     // this and t are ObjectTypes, see above.
    323     ObjectType thiz = (ObjectType) this;
    324     ObjectType other = (ObjectType) t;
    325     JavaClass[] thiz_sups = Repository.getSuperClasses(thiz.getClassName());
    326     JavaClass[] other_sups = Repository.getSuperClasses(other.getClassName());
    327
    328     if ((thiz_sups == null) || (other_sups == null)) {
    329       return null;
    330     }
    331
    332     // Waaahh...
    333     JavaClass[] this_sups = new JavaClass[thiz_sups.length + 1];
    334     JavaClass[] t_sups = new JavaClass[other_sups.length + 1];
    335     System.arraycopy(thiz_sups, 0, this_sups, 1, thiz_sups.length);
    336     System.arraycopy(other_sups, 0, t_sups, 1, other_sups.length);
    337     this_sups[0] = Repository.lookupClass(thiz.getClassName());
    338     t_sups[0] = Repository.lookupClass(other.getClassName());
    339
    340     for (int i = 0; i < t_sups.length; i++) {
    341       for (int j = 0; j < this_sups.length; j++) {
    342 	if (this_sups[j].equals(t_sups[i])) return new ObjectType(this_sups[j].getClassName());
    343       }
    344     }
    345
    346     // Huh? Did you ask for Type.OBJECT's superclass??
    347     return null;
    348   }
    349 }

This page was automatically generated by Maven