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 }