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: