1 cananian 1.1      // HClassUtil.java, created Fri Sep 11 09:14:23 1998 by cananian
  2 cananian 1.6      // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.6      // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1      package harpoon.Util;
  5 cananian 1.1      
  6 cananian 1.6.2.2  import harpoon.ClassFile.HClass;
  7 cananian 1.6.2.10 import harpoon.ClassFile.Linker;
  8 cananian 1.6.2.2  
  9 cananian 1.11     import net.cscott.jutil.Util;
 10 cananian 1.1      /**
 11 cananian 1.1       * <code>HClassUtil</code> contains various useful methods for dealing with
 12 cananian 1.1       * HClasses that do not seem to belong with the standard HClass methods.
 13 cananian 1.1       * 
 14 cananian 1.1       * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 15 cananian 1.11      * @version $Id: HClassUtil.java,v 1.11 2004/02/08 01:56:15 cananian Exp $
 16 cananian 1.1       */
 17 cananian 1.5      public abstract class HClassUtil  {
 18 cananian 1.5          // Only static methods.
 19 cananian 1.1          
 20 cananian 1.1          /** Count the number of dimensions of an array type.
 21 cananian 1.1           *  @return 0 for a non-array, n for an n-dimensional array type.
 22 cananian 1.1           */
 23 cananian 1.1          public static final int dims(HClass hc) {
 24 cananian 1.1              int i;
 25 cananian 1.1              for (i=0; hc.isArray(); i++)
 26 cananian 1.1                  hc = hc.getComponentType();
 27 cananian 1.1              return i;
 28 cananian 1.1          }
 29 cananian 1.1          /** Return the ultimate component type of an array (that is, after
 30 cananian 1.4           *  all array dimensions have been stripped off). 
 31 cananian 1.1           * @return input class <code>hc</code> if <code>hc</code> is not an
 32 cananian 1.1           *         array, otherwise a component class <code>c</code> where
 33 cananian 1.1           *         <code>c</code> is not an array. */
 34 cananian 1.1          public static final HClass baseClass(HClass hc) {
 35 cananian 1.1              while (hc.isArray())
 36 cananian 1.1                  hc = hc.getComponentType();
 37 cananian 1.1              return hc;
 38 cananian 1.1          }
 39 cananian 1.1          /** Make an n-dimensional array class from the given component class.
 40 cananian 1.1           *  The parameter <code>dims</code> is the number of array dimensions
 41 cananian 1.1           *  to add. */
 42 cananian 1.6.2.10     public static final HClass arrayClass(Linker linker, HClass hc, int dims) {
 43 cananian 1.10             assert dims>=0;
 44 cananian 1.1              StringBuffer sb = new StringBuffer();
 45 cananian 1.6.2.10         return linker.forDescriptor(Util.repeatString("[",dims)+
 46 cananian 1.6.2.8                                              hc.getDescriptor());
 47 cananian 1.2          }
 48 cananian 1.2          /** Create an array describing the inheritance of class hc.
 49 cananian 1.2           * @return an array, where element 0 is the HClass for java.lang.Object,
 50 cananian 1.2           *         an the last element is hc.
 51 cananian 1.2           */
 52 cananian 1.2          public static final HClass[] parents(HClass hc) {
 53 cananian 1.2              int len=0;
 54 cananian 1.2              for (HClass h=hc; h!=null; h=h.getSuperclass())
 55 cananian 1.2                  len++;
 56 cananian 1.2              HClass[] r = new HClass[len];
 57 cananian 1.2              for (len--; len>=0 && hc!=null; hc=hc.getSuperclass(), len--)
 58 cananian 1.2                  r[len] = hc;
 59 cananian 1.2              return r;
 60 cananian 1.2          }
 61 cananian 1.6.2.9      /** Find and return the first common superclass of a pair of classes.
 62 cananian 1.6.2.9       *  Not valid for interface or array types --- both <code>a</code>
 63 cananian 1.6.2.9       *  and <code>b</code> must be primitive or simple object types.
 64 cananian 1.6.2.9       */
 65 cananian 1.2          public static final HClass commonSuper(HClass a, HClass b) {
 66 cananian 1.8.2.1          assert !a.isInterface() && !b.isInterface();
 67 cananian 1.8.2.1          assert !a.isArray() && !b.isArray();
 68 cananian 1.6.2.4          if (a.isPrimitive() || b.isPrimitive()) {
 69 cananian 1.8.2.1              assert a==b : "Can't merge differing primitive types. "+
 70 cananian 1.8.2.1                          "("+a+" and "+b+")";
 71 cananian 1.6.2.4              return a;
 72 duncan   1.6.2.3          }
 73 duncan   1.6.2.3  
 74 cananian 1.2              HClass[] A = parents(a);
 75 cananian 1.2              HClass[] B = parents(b);
 76 cananian 1.6.2.6          // both A[0] and B[0] should be java.lang.Object.
 77 cananian 1.8.2.1          assert A[0]==B[0] : ("Hierarchy roots differ: "+A[0]+"/"+B[0]);
 78 cananian 1.2              int i;
 79 cananian 1.2              for(i=1; i<A.length && i<B.length; i++)
 80 cananian 1.2                  if (A[i] != B[i]) break;
 81 cananian 1.2              // A[i] and B[i] now point to the first *different* parent.
 82 cananian 1.2              return A[i-1];
 83 cananian 1.6.2.7      }
 84 cananian 1.6.2.9      /** Find and return the first common superinterface of a pair of
 85 cananian 1.6.2.9       *  interfaces. */
 86 cananian 1.6.2.7      public static final HClass commonInterface(HClass a, HClass b) {
 87 cananian 1.8.2.1          assert a.isInterface() && b.isInterface();
 88 cananian 1.8.2.1          assert !a.isArray() && !b.isArray();
 89 cananian 1.6.2.7          // this is a quick hack.
 90 cananian 1.6.2.7          if (a.isSuperinterfaceOf(b)) return a;
 91 cananian 1.6.2.7          if (b.isSuperinterfaceOf(a)) return b;
 92 cananian 1.8.2.1          assert !a.isPrimitive(); // getLinker() won't work in this case
 93 cananian 1.6.2.8          return a.getLinker().forName("java.lang.Object");
 94 cananian 1.6.2.7      }
 95 cananian 1.10         /** Find a class which is a common parent of both supplied classes.
 96 cananian 1.6.2.9       *  Valid for array, interface, and primitive types.
 97 cananian 1.6.2.9       */
 98 cananian 1.6.2.7      public static final HClass commonParent(HClass a, HClass b) {
 99 cananian 1.6.2.8          if (a.isPrimitive() || b.isPrimitive()) return commonSuper(a, b);
100 cananian 1.6.2.10         // note that using getLinker() is safe because neither a nor b
101 cananian 1.6.2.10         // is primitive by this point.
102 cananian 1.8.2.1          assert a.getLinker()==b.getLinker();
103 cananian 1.6.2.7          if (a.isArray() && b.isArray()) {
104 cananian 1.6.2.11             Linker linker = a.getLinker();
105 cananian 1.6.2.7              int ad = dims(a), bd = dims(b), d = (ad<bd)?ad:bd;
106 cananian 1.6.2.7              for (int i=0; i<d; i++)
107 cananian 1.6.2.7                  { a=a.getComponentType(); b=b.getComponentType(); }
108 cananian 1.10                 // merging two differing primitive arrays should result in
109 cananian 1.10                 // type 'Object'; e.g. float[][] merge int[][] = Object[]
110 cananian 1.10                 if (a.isPrimitive() && b.isPrimitive() && a!=b)
111 cananian 1.10                     return arrayClass(linker,
112 cananian 1.10                                       linker.forName("java.lang.Object"), d-1);
113 cananian 1.10                 // otherwise, find the commonParent of the components
114 cananian 1.10                 // (at least one is not an array now) and rebuild into array
115 cananian 1.10                 assert (!a.isArray()) || (!b.isArray());
116 cananian 1.6.2.11             return arrayClass(linker, commonParent(a, b), d);
117 cananian 1.6.2.7          }
118 cananian 1.6.2.7          if (a.isInterface() && b.isInterface())
119 cananian 1.6.2.7              return commonInterface(a, b);
120 cananian 1.6.2.7          if (b.isArray()) return commonParent(b,a);
121 cananian 1.6.2.7          if (a.isArray()) // b is interface or object, not array.
122 cananian 1.6.2.8              if (b==b.getLinker().forName("java.lang.Cloneable") ||
123 cananian 1.6.2.8                  b==b.getLinker().forName("java.io.Serializable"))
124 cananian 1.6.2.7                  return b;
125 cananian 1.6.2.8              else return b.getLinker().forName("java.lang.Object");
126 cananian 1.6.2.7          if (b.isInterface()) return commonParent(b,a);
127 cananian 1.6.2.7          if (a.isInterface()) // b is object
128 cananian 1.6.2.7              if (a.isSuperinterfaceOf(b)) return a;
129 cananian 1.6.2.8              else return a.getLinker().forName("java.lang.Object");
130 cananian 1.6.2.7          // both a and b are object.
131 cananian 1.6.2.7          return commonSuper(a,b);
132 cananian 1.1          }
133 cananian 1.1      }