001 package serp.bytecode;
002
003 import serp.bytecode.visitor.*;
004 import serp.util.*;
005
006 /**
007 * A method of a class.
008 *
009 * @author Abe White
010 */
011 public class BCMethod extends BCMember implements VisitAcceptor {
012 BCMethod(BCClass owner) {
013 super(owner);
014 }
015
016 /////////////////////
017 // Access operations
018 /////////////////////
019
020 /**
021 * Manipulate the method access flags.
022 */
023 public boolean isSynchronized() {
024 return (getAccessFlags() & Constants.ACCESS_SYNCHRONIZED) > 0;
025 }
026
027 /**
028 * Manipulate the method access flags.
029 */
030 public void setSynchronized(boolean on) {
031 if (on)
032 setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNCHRONIZED);
033 else
034 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNCHRONIZED);
035 }
036
037 /**
038 * Manipulate the method access flags.
039 */
040 public boolean isNative() {
041 return (getAccessFlags() & Constants.ACCESS_NATIVE) > 0;
042 }
043
044 /**
045 * Manipulate the method access flags.
046 */
047 public void setNative(boolean on) {
048 if (on)
049 setAccessFlags(getAccessFlags() | Constants.ACCESS_NATIVE);
050 else
051 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_NATIVE);
052 }
053
054 /**
055 * Manipulate the method access flags.
056 */
057 public boolean isAbstract() {
058 return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0;
059 }
060
061 /**
062 * Manipulate the method access flags.
063 */
064 public void setAbstract(boolean on) {
065 if (on)
066 setAccessFlags(getAccessFlags() | Constants.ACCESS_ABSTRACT);
067 else
068 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ABSTRACT);
069 }
070
071 /**
072 * Manipulate the method access flags.
073 */
074 public boolean isStrict() {
075 return (getAccessFlags() & Constants.ACCESS_STRICT) > 0;
076 }
077
078 /**
079 * Manipulate the method access flags.
080 */
081 public void setStrict(boolean on) {
082 if (on)
083 setAccessFlags(getAccessFlags() | Constants.ACCESS_STRICT);
084 else
085 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STRICT);
086 }
087
088 /**
089 * Manipulate the method access flags.
090 */
091 public boolean isVarArgs() {
092 return (getAccessFlags() & Constants.ACCESS_VARARGS) > 0;
093 }
094
095 /**
096 * Manipulate the method access flags.
097 */
098 public void setVarArgs(boolean on) {
099 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 }