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 }