View Javadoc

1   package serp.bytecode;
2   
3   import serp.bytecode.visitor.*;
4   import serp.util.*;
5   
6   /***
7    * A method of a class.
8    *
9    * @author Abe White
10   */
11  public class BCMethod extends BCMember implements VisitAcceptor {
12      BCMethod(BCClass owner) {
13          super(owner);
14      }
15  
16      /////////////////////
17      // Access operations
18      /////////////////////
19  
20      /***
21       * Manipulate the method access flags.
22       */
23      public boolean isSynchronized() {
24          return (getAccessFlags() & Constants.ACCESS_SYNCHRONIZED) > 0;
25      }
26  
27      /***
28       * Manipulate the method access flags.
29       */
30      public void setSynchronized(boolean on) {
31          if (on)
32              setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNCHRONIZED);
33          else
34              setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNCHRONIZED);
35      }
36  
37      /***
38       * Manipulate the method access flags.
39       */
40      public boolean isNative() {
41          return (getAccessFlags() & Constants.ACCESS_NATIVE) > 0;
42      }
43  
44      /***
45       * Manipulate the method access flags.
46       */
47      public void setNative(boolean on) {
48          if (on)
49              setAccessFlags(getAccessFlags() | Constants.ACCESS_NATIVE);
50          else
51              setAccessFlags(getAccessFlags() & ~Constants.ACCESS_NATIVE);
52      }
53  
54      /***
55       * Manipulate the method access flags.
56       */
57      public boolean isAbstract() {
58          return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0;
59      }
60  
61      /***
62       * Manipulate the method access flags.
63       */
64      public void setAbstract(boolean on) {
65          if (on)
66              setAccessFlags(getAccessFlags() | Constants.ACCESS_ABSTRACT);
67          else
68              setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ABSTRACT);
69      }
70  
71      /***
72       * Manipulate the method access flags.
73       */
74      public boolean isStrict() {
75          return (getAccessFlags() & Constants.ACCESS_STRICT) > 0;
76      }
77  
78      /***
79       * Manipulate the method access flags.
80       */
81      public void setStrict(boolean on) {
82          if (on)
83              setAccessFlags(getAccessFlags() | Constants.ACCESS_STRICT);
84          else
85              setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STRICT);
86      }
87  
88      /***
89       * Manipulate the method access flags.
90       */
91      public boolean isVarArgs() {
92          return (getAccessFlags() & Constants.ACCESS_VARARGS) > 0;
93      }
94  
95      /***
96       * Manipulate the method access flags.
97       */
98      public void setVarArgs(boolean on) {
99          if (on)
100             setAccessFlags(getAccessFlags() | Constants.ACCESS_VARARGS);
101         else
102             setAccessFlags(getAccessFlags() & ~Constants.ACCESS_VARARGS);
103     }
104 
105     /***
106      * Manipulate the method access flags.
107      */
108     public boolean isBridge() {
109         return (getAccessFlags() & Constants.ACCESS_BRIDGE) > 0;
110     }
111 
112     /***
113      * Manipulate the method access flags.
114      */
115     public void setBridge(boolean on) {
116         if (on)
117             setAccessFlags(getAccessFlags() | Constants.ACCESS_BRIDGE);
118         else
119             setAccessFlags(getAccessFlags() & ~Constants.ACCESS_BRIDGE);
120     }
121 
122     /////////////////////
123     // Return operations
124     /////////////////////
125 
126     /***
127      * Return the name of the type returned by this method. The name
128      * will be given in a form suitable for a {@link Class#forName} call.
129      *
130      * @see BCMember#getDescriptor
131      */
132     public String getReturnName() {
133         return getProject().getNameCache().getExternalForm(getProject().
134             getNameCache().getDescriptorReturnName(getDescriptor()), false);
135     }
136 
137     /***
138      * Return the {@link Class} object for the return type of this method.
139      *
140      * @see BCMember#getDescriptor
141      */
142     public Class getReturnType() {
143         return Strings.toClass(getReturnName(), getClassLoader());
144     }
145 
146     /***
147      * Return the bytecode for the return type of this method.
148      *
149      * @see BCMember#getDescriptor
150      */
151     public BCClass getReturnBC() {
152         return getProject().loadClass(getReturnName(), getClassLoader());
153     }
154 
155     /***
156      * Set the return type of this method.
157      */
158     public void setReturn(String name) {
159         setDescriptor(getProject().getNameCache().getDescriptor(name, 
160             getParamNames()));
161     }
162 
163     /***
164      * Set the return type of this method.
165      */
166     public void setReturn(Class type) {
167         setReturn(type.getName());
168     }
169 
170     /***
171      * Set the return type of this method.
172      */
173     public void setReturn(BCClass type) {
174         setReturn(type.getName());
175     }
176 
177     ////////////////////////
178     // Parameter operations
179     ////////////////////////
180 
181     /***
182      * Return the names of all the parameter types for this method. The names
183      * will be returned in a form suitable for a {@link Class#forName} call.
184      *
185      * @see BCMember#getDescriptor
186      */
187     public String[] getParamNames() {
188         // get the parameter types from the descriptor
189         String[] params = getProject().getNameCache().getDescriptorParamNames
190             (getDescriptor());
191 
192         // convert them to external form
193         for (int i = 0; i < params.length; i++)
194             params[i] = getProject().getNameCache().getExternalForm(params[i], 
195                 false);
196         return params;
197     }
198 
199     /***
200      * Return the {@link Class} objects for all the parameter types for this
201      * method.
202      *
203      * @see BCMember#getDescriptor
204      */
205     public Class[] getParamTypes() {
206         String[] paramNames = getParamNames();
207         Class[] params = new Class[paramNames.length];
208         for (int i = 0; i < paramNames.length; i++)
209             params[i] = Strings.toClass(paramNames[i], getClassLoader());
210         return params;
211     }
212 
213     /***
214      * Return the bytecode for all the parameter types for this method.
215      *
216      * @see BCMember#getDescriptor
217      */
218     public BCClass[] getParamBCs() {
219         String[] paramNames = getParamNames();
220         BCClass[] params = new BCClass[paramNames.length];
221         for (int i = 0; i < paramNames.length; i++)
222             params[i] = getProject().loadClass(paramNames[i], getClassLoader());
223         return params;
224     }
225 
226     /***
227      * Set the parameter types of this method.
228      *
229      * @see BCMember#setDescriptor
230      */
231     public void setParams(String[] names) {
232         if (names == null)
233             names = new String[0];
234         setDescriptor(getProject().getNameCache().getDescriptor(getReturnName(),
235             names));
236     }
237 
238     /***
239      * Set the parameter type of this method.
240      *
241      * @see BCMember#setDescriptor
242      */
243     public void setParams(Class[] types) {
244         if (types == null)
245             setParams((String[]) null);
246         else {
247             String[] names = new String[types.length];
248             for (int i = 0; i < types.length; i++)
249                 names[i] = types[i].getName();
250             setParams(names);
251         }
252     }
253 
254     /***
255      * Set the parameter type of this method.
256      *
257      * @see BCMember#setDescriptor
258      */
259     public void setParams(BCClass[] types) {
260         if (types == null)
261             setParams((String[]) null);
262         else {
263             String[] names = new String[types.length];
264             for (int i = 0; i < types.length; i++)
265                 names[i] = types[i].getName();
266             setParams(names);
267         }
268     }
269 
270     /***
271      * Add a parameter type to this method.
272      */
273     public void addParam(String type) {
274         String[] origParams = getParamNames();
275         String[] params = new String[origParams.length + 1];
276         for (int i = 0; i < origParams.length; i++)
277             params[i] = origParams[i];
278         params[origParams.length] = type;
279         setParams(params);
280     }
281 
282     /***
283      * Add a parameter type to this method.
284      */
285     public void addParam(Class type) {
286         addParam(type.getName());
287     }
288 
289     /***
290      * Add a parameter type to this method.
291      */
292     public void addParam(BCClass type) {
293         addParam(type.getName());
294     }
295 
296     /***
297      * Add a parameter type to this method.
298      *
299      * @see java.util.List#add(int,Object)
300      */
301     public void addParam(int pos, String type) {
302         String[] origParams = getParamNames();
303         if ((pos < 0) || (pos >= origParams.length))
304             throw new IndexOutOfBoundsException("pos = " + pos);
305 
306         String[] params = new String[origParams.length + 1];
307         for (int i = 0, index = 0; i < params.length; i++) {
308             if (i == pos)
309                 params[i] = type;
310             else
311                 params[i] = origParams[index++];
312         }
313         setParams(params);
314     }
315 
316     /***
317      * Add a parameter type to this method.
318      *
319      * @see java.util.List#add(int,Object)
320      */
321     public void addParam(int pos, Class type) {
322         addParam(pos, type.getName());
323     }
324 
325     /***
326      * Add a parameter type to this method.
327      *
328      * @see java.util.List#add(int,Object)
329      */
330     public void addParam(int pos, BCClass type) {
331         addParam(pos, type.getName());
332     }
333 
334     /***
335      * Change a parameter type of this method.
336      *
337      * @see java.util.List#set(int,Object)
338      */
339     public void setParam(int pos, String type) {
340         String[] origParams = getParamNames();
341         if ((pos < 0) || (pos >= origParams.length))
342             throw new IndexOutOfBoundsException("pos = " + pos);
343 
344         String[] params = new String[origParams.length];
345         for (int i = 0; i < params.length; i++) {
346             if (i == pos)
347                 params[i] = type;
348             else
349                 params[i] = origParams[i];
350         }
351         setParams(params);
352     }
353 
354     /***
355      * Change a parameter type of this method.
356      *
357      * @see java.util.List#set(int,Object)
358      */
359     public void setParam(int pos, Class type) {
360         setParam(pos, type.getName());
361     }
362 
363     /***
364      * Change a parameter type of this method.
365      *
366      * @see java.util.List#set(int,Object)
367      */
368     public void setParam(int pos, BCClass type) {
369         setParam(pos, type.getName());
370     }
371 
372     /***
373      * Clear all parameters from this method.
374      */
375     public void clearParams() {
376         setParams((String[]) null);
377     }
378 
379     /***
380      * Remove a parameter from this method.
381      */
382     public void removeParam(int pos) {
383         String[] origParams = getParamNames();
384         if ((pos < 0) || (pos >= origParams.length))
385             throw new IndexOutOfBoundsException("pos = " + pos);
386 
387         String[] params = new String[origParams.length - 1];
388 
389         for (int i = 0, index = 0; i < origParams.length; i++)
390             if (i != pos)
391                 params[index++] = origParams[i];
392         setParams(params);
393     }
394 
395     ///////////////////////
396     // Convenience methods
397     ///////////////////////
398 
399     /***
400      * Return the checked exceptions information for the method.
401      * Acts internally through the {@link Attributes} interface.
402      *
403      * @param add if true, a new exceptions attribute will be added
404      * if not already present
405      * @return the exceptions information, or null if none and the
406      * <code>add</code> param is set to false
407      */
408     public Exceptions getExceptions(boolean add) {
409         Exceptions exceptions = (Exceptions) getAttribute
410             (Constants.ATTR_EXCEPTIONS);
411         if (!add || (exceptions != null))
412             return exceptions;
413 
414         if (exceptions == null)
415             exceptions = (Exceptions) addAttribute(Constants.ATTR_EXCEPTIONS);
416         return exceptions;
417     }
418 
419     /***
420      * Remove the exceptions attribute for the method.
421      * Acts internally through the {@link Attributes} interface.
422      *
423      * @return true if there was a value to remove
424      */
425     public boolean removeExceptions() {
426         return removeAttribute(Constants.ATTR_EXCEPTIONS);
427     }
428 
429     /***
430      * Return the code for the method. If the code already exists, its
431      * iterator will be reset to the first instruction.
432      * Acts internally through the {@link Attributes} interface.
433      *
434      * @param add if true, a new code attribute will be added
435      * if not already present
436      * @return the code for the metohd, or null if none and the
437      * <code>add</code> param is set to false
438      */
439     public Code getCode(boolean add) {
440         Code code = (Code) getAttribute(Constants.ATTR_CODE);
441         if (code != null) {
442             code.beforeFirst();
443             return code;
444         }
445         if (!add)
446             return null;
447         return (Code) addAttribute(Constants.ATTR_CODE);
448     }
449 
450     /***
451      * Remove the code attribute from the method.
452      * Acts internally through the {@link Attributes} interface.
453      *
454      * @return true if there was a value to remove
455      */
456     public boolean removeCode() {
457         return removeAttribute(Constants.ATTR_CODE);
458     }
459 
460     ////////////////////////////////
461     // VisitAcceptor implementation
462     ////////////////////////////////
463 
464     public void acceptVisit(BCVisitor visit) {
465         visit.enterBCMethod(this);
466         visitAttributes(visit);
467         visit.exitBCMethod(this);
468     }
469 
470     void initialize(String name, String descriptor) {
471         super.initialize(name, descriptor);
472         makePublic();
473     }
474 }