1 cananian 1.1.4.1 // HMethod.java, created Fri Jul 31 22:02:43 1998 by cananian 2 cananian 1.1.4.1 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.4.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.4.1 package harpoon.ClassFile; 5 cananian 1.1.4.1 6 cananian 1.1.4.1 import harpoon.Util.Util; 7 cananian 1.1.4.1 import harpoon.Util.ArrayFactory; 8 cananian 1.1.4.1 9 cananian 1.1.4.1 import java.lang.reflect.Modifier; 10 cananian 1.1.4.1 import java.util.Hashtable; 11 cananian 1.1.4.1 /** 12 cananian 1.1.4.1 * <code>HMethodImpl</code> is the basic implementation of 13 cananian 1.1.4.1 * <code>HMethod</code>. 14 cananian 1.1.4.1 * 15 cananian 1.1.4.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 16 cananian 1.4 * @version $Id: HMethodImpl.java,v 1.4 2003/03/18 02:27:02 cananian Exp $ 17 cananian 1.1.4.1 * @see HMethod 18 cananian 1.1.4.1 */ 19 cananian 1.1.4.1 abstract class HMethodImpl 20 cananian 1.2.2.1 implements HMethod, java.io.Serializable, java.lang.Comparable<HMember> { 21 cananian 1.1.4.1 HClass parent; 22 cananian 1.1.4.1 String name; 23 cananian 1.1.4.1 int modifiers; 24 cananian 1.1.4.1 HPointer returnType; 25 cananian 1.1.4.1 HPointer[] parameterTypes; 26 cananian 1.1.4.1 String[] parameterNames; 27 cananian 1.1.4.1 HPointer[] exceptionTypes; 28 cananian 1.1.4.1 boolean isSynthetic; 29 cananian 1.1.4.1 30 cananian 1.1.4.1 /** 31 cananian 1.1.4.1 * Returns the <code>HClass</code> object representing the class or 32 cananian 1.1.4.1 * interface that declares the method represented by this 33 cananian 1.1.4.1 * <code>HMethod</code> object. 34 cananian 1.1.4.1 */ 35 cananian 1.1.4.1 public HClass getDeclaringClass() { 36 cananian 1.1.4.1 return parent; 37 cananian 1.1.4.1 } 38 cananian 1.1.4.1 39 cananian 1.1.4.1 /** 40 cananian 1.1.4.1 * Returns the name of the method represented by this <code>HMethod</code> 41 cananian 1.1.4.1 * object, as a <code>String</code>. 42 cananian 1.1.4.1 */ 43 cananian 1.1.4.1 public String getName() { 44 cananian 1.1.4.1 return name; 45 cananian 1.1.4.1 } 46 cananian 1.1.4.1 47 cananian 1.1.4.1 /** 48 cananian 1.1.4.1 * Returns the Java language modifiers for the method represented by this 49 cananian 1.1.4.1 * <code>HMethod</code> object, as an integer. The 50 cananian 1.1.4.1 * <code>java.lang.reflect.Modifier</code> 51 cananian 1.1.4.1 * class should be used to decode the modifiers. 52 cananian 1.1.4.1 * @see java.lang.reflect.Modifier 53 cananian 1.1.4.1 */ 54 cananian 1.1.4.1 public int getModifiers() { 55 cananian 1.1.4.1 return modifiers; 56 cananian 1.1.4.1 } 57 cananian 1.1.4.1 58 cananian 1.1.4.1 /** 59 cananian 1.1.4.1 * Returns a <code>HClass</code> object that represents the formal 60 cananian 1.1.4.1 * return type of the method represented by this <code>HMethod</code> 61 cananian 1.1.4.1 * object. 62 cananian 1.1.4.1 */ 63 cananian 1.1.4.1 public HClass getReturnType() { 64 cananian 1.1.4.1 try { 65 cananian 1.1.4.1 return (HClass) returnType; 66 cananian 1.1.4.1 } catch (ClassCastException e) { // returnType was ClassPointer 67 cananian 1.1.4.1 HClass rt = returnType.actual(); 68 cananian 1.1.4.1 returnType = rt; 69 cananian 1.1.4.1 return rt; 70 cananian 1.1.4.1 } 71 cananian 1.1.4.1 } 72 cananian 1.1.4.1 73 cananian 1.1.4.1 /** 74 cananian 1.1.4.1 * Returns the descriptor for this method. 75 cananian 1.1.4.1 */ 76 cananian 1.1.4.1 public String getDescriptor() { 77 cananian 1.1.4.1 StringBuffer sb = new StringBuffer("("); 78 cananian 1.1.4.1 for (int i=0; i<parameterTypes.length; i++) 79 cananian 1.1.4.1 sb.append(parameterTypes[i].getDescriptor()); 80 cananian 1.1.4.1 sb.append(')'); 81 cananian 1.1.4.1 sb.append(returnType.getDescriptor()); 82 cananian 1.1.4.1 return sb.toString(); 83 cananian 1.1.4.1 } 84 cananian 1.1.4.1 85 cananian 1.1.4.1 /** 86 cananian 1.1.4.1 * Returns an array of <code>HClass</code> objects that represent the 87 cananian 1.1.4.1 * formal parameter types, in declaration order, of the method 88 cananian 1.1.4.1 * represented by this <code>HMethod</code> object. Returns an array 89 cananian 1.1.4.1 * of length 0 is the underlying method takes no parameters. 90 cananian 1.1.4.1 */ 91 cananian 1.1.4.1 public HClass[] getParameterTypes() { 92 cananian 1.1.4.1 HClass[] pt; 93 cananian 1.1.4.1 try { 94 cananian 1.1.4.1 pt = (HClass[]) parameterTypes; 95 cananian 1.1.4.1 } catch (ClassCastException e) { // parameterTypes was ClassPointer[] 96 cananian 1.1.4.1 pt = new HClass[parameterTypes.length]; 97 cananian 1.1.4.1 for (int i=0; i<pt.length; i++) 98 cananian 1.1.4.1 pt[i] = parameterTypes[i].actual(); 99 cananian 1.1.4.1 parameterTypes = pt; 100 cananian 1.1.4.1 } 101 cananian 1.1.4.1 return (HClass[]) Util.safeCopy(HClass.arrayFactory, pt); 102 cananian 1.1.4.1 } 103 cananian 1.1.4.1 104 cananian 1.1.4.1 /** 105 cananian 1.1.4.1 * Returns an array of <code>String</code> objects giving the declared 106 cananian 1.1.4.1 * names of the formal parameters of the method. The length of the 107 cananian 1.1.4.1 * returned array is equal to the number of formal parameters. 108 cananian 1.1.4.1 * If there is no <code>LocalVariableTable</code> attribute available 109 cananian 1.1.4.1 * for this method, then every element of the returned array will be 110 cananian 1.1.4.1 * <code>null</code>. 111 cananian 1.1.4.1 */ 112 cananian 1.1.4.1 public String[] getParameterNames() { 113 cananian 1.2.2.1 return Util.safeCopy(new ArrayFactory<String>() { 114 cananian 1.2.2.1 public String[] newArray(int len) { return new String[len]; } 115 cananian 1.1.4.1 }, parameterNames); 116 cananian 1.1.4.1 } 117 cananian 1.1.4.1 118 cananian 1.1.4.1 /** 119 cananian 1.1.4.1 * Returns an array of <code>HClass</code> objects that represent the 120 cananian 1.1.4.1 * types of the checked exceptions thrown by the underlying method 121 cananian 1.1.4.1 * represented by this <code>HMethod</code> object. Returns an array 122 cananian 1.1.4.1 * of length 0 if the method throws no checked exceptions. 123 cananian 1.1.4.1 */ 124 cananian 1.1.4.1 public HClass[] getExceptionTypes() { 125 cananian 1.1.4.1 HClass[] et; 126 cananian 1.1.4.1 try { 127 cananian 1.1.4.1 et = (HClass[]) exceptionTypes; 128 cananian 1.1.4.1 } catch (ClassCastException e) { // exceptionTypes was ClassPointer 129 cananian 1.1.4.1 et = new HClass[exceptionTypes.length]; 130 cananian 1.1.4.1 for (int i=0; i<et.length; i++) 131 cananian 1.1.4.1 et[i] = exceptionTypes[i].actual(); 132 cananian 1.1.4.1 exceptionTypes = et; 133 cananian 1.1.4.1 } 134 cananian 1.1.4.1 return (HClass[]) Util.safeCopy(HClass.arrayFactory, et); 135 cananian 1.1.4.1 } 136 cananian 1.1.4.1 137 cananian 1.1.4.1 /** 138 cananian 1.1.4.1 * Determines whether this <code>HMethod</code> is synthetic. 139 cananian 1.1.4.1 */ 140 cananian 1.1.4.1 public boolean isSynthetic() { return isSynthetic; } 141 cananian 1.1.4.1 142 cananian 1.1.4.1 /** Determines whether this <code>HMethod</code> is an interface method. */ 143 cananian 1.1.4.1 public boolean isInterfaceMethod() { 144 cananian 1.1.4.2 return parent.isInterface() && !(this instanceof HInitializer); 145 cananian 1.1.4.1 } 146 cananian 1.1.4.1 /** Determines whether this is a static method. */ 147 cananian 1.1.4.1 public boolean isStatic() { 148 cananian 1.1.4.1 return Modifier.isStatic(getModifiers()); 149 cananian 1.1.4.1 } 150 cananian 1.4 151 cananian 1.4 /* ------- JSR-14 extensions. ----------- */ 152 cananian 1.4 public HType[] getGenericParameterTypes() { 153 cananian 1.4 throw new RuntimeException("Unimplemented."); 154 cananian 1.4 } 155 cananian 1.4 public HType getGenericReturnType() { 156 cananian 1.4 throw new RuntimeException("Unimplemented."); 157 cananian 1.4 } 158 cananian 1.4 public HMethodTypeVariable[] getTypeParameters() { 159 cananian 1.4 throw new RuntimeException("Unimplemented."); 160 cananian 1.4 } 161 cananian 1.4 162 cananian 1.1.4.1 163 cananian 1.1.4.1 /** Returns a mutator for this <code>HMethod</code>, or <code>null</code> 164 cananian 1.1.4.1 * if the object is immutable. */ 165 cananian 1.1.4.1 public HMethodMutator getMutator() { return null; } 166 cananian 1.1.4.1 167 cananian 1.1.4.1 /** 168 cananian 1.1.4.1 * Compares this <code>HMethod</code> against the specified object. 169 cananian 1.1.4.1 * Returns <code>true</code> if the objects are the same. Two 170 cananian 1.1.4.1 * <code>HMethod</code>s are the same if they were declared by the same 171 cananian 1.1.4.1 * class and have the same name and formal parameter types. 172 cananian 1.1.4.1 */ // in actual practice, I think HMethods are unique. 173 cananian 1.1.4.6 public boolean equals(Object obj) { return equals(this, obj); } 174 cananian 1.1.4.6 // factored out for re-use. 175 cananian 1.1.4.6 static boolean equals(HMethod _this_, Object obj) { 176 cananian 1.1.4.1 HMethod method; 177 cananian 1.1.4.1 if (obj==null) return false; 178 cananian 1.1.4.6 if (_this_==obj) return true; // common case. 179 cananian 1.1.4.1 try { method = (HMethod) obj; } 180 cananian 1.1.4.1 catch (ClassCastException e) { return false; } 181 cananian 1.1.4.6 if (!_this_.getDeclaringClass().getDescriptor().equals 182 cananian 1.1.4.1 (method.getDeclaringClass().getDescriptor())) return false; 183 cananian 1.1.4.6 if (!_this_.getName().equals(method.getName())) return false; 184 cananian 1.1.4.6 HClass hc1[] = _this_.getParameterTypes(); 185 cananian 1.1.4.1 HClass hc2[] = method.getParameterTypes(); 186 cananian 1.1.4.1 if (hc1.length != hc2.length) return false; 187 cananian 1.1.4.1 for (int i=0; i<hc1.length; i++) 188 cananian 1.1.4.1 if (!hc1[i].getDescriptor().equals(hc2[i].getDescriptor())) 189 cananian 1.1.4.1 return false; 190 cananian 1.1.4.1 return true; 191 cananian 1.1.4.1 } 192 cananian 1.1.4.1 193 cananian 1.1.4.6 public int hashCode() { return hashCode(this); } 194 cananian 1.1.4.6 // factored out for re-use 195 cananian 1.1.4.6 static int hashCode(HMethod hm) { 196 cananian 1.1.4.6 return 197 cananian 1.1.4.6 hm.getDeclaringClass().hashCode() ^ 198 cananian 1.1.4.6 hm.getName().hashCode() ^ 199 cananian 1.1.4.6 hm.getDescriptor().hashCode(); 200 cananian 1.1.4.1 } 201 cananian 1.1.4.1 202 cananian 1.1.4.1 /** 203 cananian 1.1.4.1 * Returns a string describing this <code>HMethod</code>. The string 204 cananian 1.1.4.1 * is formatted as the method access modifiers, if any, followed by 205 cananian 1.1.4.1 * the method return type, followed by a space, followed by the class 206 cananian 1.1.4.1 * declaring the method, followed by a period, followed by the method 207 cananian 1.1.4.1 * name, followed by a parenthesized, comma-separated list of the 208 cananian 1.1.4.1 * method's formal parameter types. If the method throws checked 209 cananian 1.1.4.1 * exceptions, the parameter list is followed by a space, followed 210 cananian 1.1.4.1 * by the word throws followed by a comma-separated list of the 211 cananian 1.1.4.1 * throws exception types. For example:<p> 212 cananian 1.1.4.1 * <DL> 213 cananian 1.1.4.1 * <DD><CODE>public boolean java.lang.Object.equals(java.lang.Object)</CODE> 214 cananian 1.1.4.1 * </DL><p> 215 cananian 1.1.4.1 * The access modifiers are placed in canonical order as specified by 216 cananian 1.1.4.1 * "The Java Language Specification." This is 217 cananian 1.1.4.1 * <code>public</code>, <code>protected</code>, or <code>private</code> 218 cananian 1.1.4.1 * first, and then other modifiers in the following order: 219 cananian 1.1.4.1 * <code>abstract</code>, <code>static</code>, <code>final</code>, 220 cananian 1.1.4.1 * <code>synchronized</code>, <code>native</code>. 221 cananian 1.1.4.1 */ 222 cananian 1.1.4.6 public String toString() { return toString(this); } 223 cananian 1.1.4.6 /** For re-use by other classes implementing HMethod. */ 224 cananian 1.1.4.6 static String toString(HMethod hm) { 225 cananian 1.1.4.1 StringBuffer r = new StringBuffer(); 226 cananian 1.1.4.6 int m = hm.getModifiers(); 227 cananian 1.1.4.1 if (m!=0) { 228 cananian 1.1.4.1 r.append(Modifier.toString(m)); 229 cananian 1.1.4.1 r.append(' '); 230 cananian 1.1.4.1 } 231 cananian 1.1.4.6 r.append(HClass.getTypeName(hm.getReturnType())); 232 cananian 1.1.4.1 r.append(' '); 233 cananian 1.1.4.6 r.append(HClass.getTypeName(hm.getDeclaringClass())); 234 cananian 1.1.4.1 r.append('.'); 235 cananian 1.1.4.6 r.append(hm.getName()); 236 cananian 1.1.4.1 r.append('('); 237 cananian 1.1.4.6 HPointer hcp[] = hm.getParameterTypes(); 238 cananian 1.1.4.1 for (int i=0; i<hcp.length; i++) { 239 cananian 1.1.4.1 r.append(HClass.getTypeName(hcp[i])); 240 cananian 1.1.4.1 if (i < hcp.length-1) 241 cananian 1.1.4.1 r.append(','); 242 cananian 1.1.4.1 } 243 cananian 1.1.4.1 r.append(')'); 244 cananian 1.1.4.6 HPointer ecp[] = hm.getExceptionTypes(); 245 cananian 1.1.4.1 if (ecp.length > 0) { 246 cananian 1.1.4.1 r.append(" throws "); 247 cananian 1.1.4.1 for (int i=0; i<ecp.length; i++) { 248 cananian 1.1.4.1 r.append(ecp[i].getName()); // can't be primitive or array type. 249 cananian 1.1.4.1 if (i < ecp.length-1) 250 cananian 1.1.4.1 r.append(','); 251 cananian 1.1.4.1 } 252 cananian 1.1.4.1 } 253 cananian 1.1.4.1 return r.toString(); 254 cananian 1.1.4.1 } 255 cananian 1.1.4.1 256 cananian 1.1.4.1 /** Serializable interface. */ 257 cananian 1.1.4.1 public Object writeReplace() { return new HMethodStub(this); } 258 cananian 1.1.4.4 static final class HMethodStub implements java.io.Serializable { 259 cananian 1.1.4.1 private HClass parent; 260 cananian 1.1.4.1 private String name, descriptor; 261 cananian 1.1.4.1 HMethodStub(HMethod m) { 262 cananian 1.1.4.1 this.parent=m.getDeclaringClass(); 263 cananian 1.1.4.1 this.name=m.getName().intern(); 264 cananian 1.1.4.1 this.descriptor=m.getDescriptor().intern(); 265 cananian 1.1.4.1 } 266 cananian 1.1.4.1 public Object readResolve() { 267 cananian 1.1.4.1 return parent.getDeclaredMethod(name, descriptor); 268 cananian 1.1.4.1 } 269 cananian 1.1.4.1 } 270 cananian 1.1.4.1 // Comparable interface 271 cananian 1.1.4.1 /** Compares two <code>HMethod</code>s lexicographically; first by 272 cananian 1.1.4.1 * declaring class, then by name, and lastly by descriptor. */ 273 cananian 1.2.2.1 public int compareTo(HMember o) { 274 cananian 1.1.4.3 return memberComparator.compare(this, o); 275 cananian 1.1.4.1 } 276 cananian 1.1.4.1 } 277 cananian 1.1.4.1 278 cananian 1.1.4.1 // set emacs indentation style. 279 cananian 1.1.4.1 // Local Variables: 280 cananian 1.1.4.1 // c-basic-offset:2 281 cananian 1.2 // End: