MethodNode.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30package org.mockito.asm.tree; 31 32import org.mockito.asm.AnnotationVisitor; 33import org.mockito.asm.Attribute; 34import org.mockito.asm.ClassVisitor; 35import org.mockito.asm.Label; 36import org.mockito.asm.MethodVisitor; 37import org.mockito.asm.Opcodes; 38import org.mockito.asm.Type; 39 40import java.util.List; 41import java.util.ArrayList; 42import java.util.Arrays; 43 44/** 45 * A node that represents a method. 46 * 47 * @author Eric Bruneton 48 */ 49public class MethodNode extends MemberNode implements MethodVisitor { 50 51 /** 52 * The method's access flags (see {@link Opcodes}). This field also 53 * indicates if the method is synthetic and/or deprecated. 54 */ 55 public int access; 56 57 /** 58 * The method's name. 59 */ 60 public String name; 61 62 /** 63 * The method's descriptor (see {@link Type}). 64 */ 65 public String desc; 66 67 /** 68 * The method's signature. May be <tt>null</tt>. 69 */ 70 public String signature; 71 72 /** 73 * The internal names of the method's exception classes (see 74 * {@link Type#getInternalName() getInternalName}). This list is a list of 75 * {@link String} objects. 76 */ 77 public List exceptions; 78 79 /** 80 * The default value of this annotation interface method. This field must be 81 * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short}, 82 * {@link Integer}, {@link Long}, {@link Float}, {@link Double}, 83 * {@link String} or {@link Type}, or an two elements String array (for 84 * enumeration values), a {@link AnnotationNode}, or a {@link List} of 85 * values of one of the preceding types. May be <tt>null</tt>. 86 */ 87 public Object annotationDefault; 88 89 /** 90 * The runtime visible parameter annotations of this method. These lists are 91 * lists of {@link AnnotationNode} objects. May be <tt>null</tt>. 92 * 93 * @associates org.mockito.asm.tree.AnnotationNode 94 * @label invisible parameters 95 */ 96 public List[] visibleParameterAnnotations; 97 98 /** 99 * The runtime invisible parameter annotations of this method. These lists 100 * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>. 101 * 102 * @associates org.mockito.asm.tree.AnnotationNode 103 * @label visible parameters 104 */ 105 public List[] invisibleParameterAnnotations; 106 107 /** 108 * The instructions of this method. This list is a list of 109 * {@link AbstractInsnNode} objects. 110 * 111 * @associates org.mockito.asm.tree.AbstractInsnNode 112 * @label instructions 113 */ 114 public InsnList instructions; 115 116 /** 117 * The try catch blocks of this method. This list is a list of 118 * {@link TryCatchBlockNode} objects. 119 * 120 * @associates org.mockito.asm.tree.TryCatchBlockNode 121 */ 122 public List tryCatchBlocks; 123 124 /** 125 * The maximum stack size of this method. 126 */ 127 public int maxStack; 128 129 /** 130 * The maximum number of local variables of this method. 131 */ 132 public int maxLocals; 133 134 /** 135 * The local variables of this method. This list is a list of 136 * {@link LocalVariableNode} objects. May be <tt>null</tt> 137 * 138 * @associates org.mockito.asm.tree.LocalVariableNode 139 */ 140 public List localVariables; 141 142 /** 143 * Constructs an unitialized {@link MethodNode}. 144 */ 145 public MethodNode() { 146 this.instructions = new InsnList(); 147 } 148 149 /** 150 * Constructs a new {@link MethodNode}. 151 * 152 * @param access the method's access flags (see {@link Opcodes}). This 153 * parameter also indicates if the method is synthetic and/or 154 * deprecated. 155 * @param name the method's name. 156 * @param desc the method's descriptor (see {@link Type}). 157 * @param signature the method's signature. May be <tt>null</tt>. 158 * @param exceptions the internal names of the method's exception classes 159 * (see {@link Type#getInternalName() getInternalName}). May be 160 * <tt>null</tt>. 161 */ 162 public MethodNode( 163 final int access, 164 final String name, 165 final String desc, 166 final String signature, 167 final String[] exceptions) 168 { 169 this(); 170 this.access = access; 171 this.name = name; 172 this.desc = desc; 173 this.signature = signature; 174 this.exceptions = new ArrayList(exceptions == null 175 ? 0 176 : exceptions.length); 177 boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; 178 if (!isAbstract) { 179 this.localVariables = new ArrayList(5); 180 } 181 this.tryCatchBlocks = new ArrayList(); 182 if (exceptions != null) { 183 this.exceptions.addAll(Arrays.asList(exceptions)); 184 } 185 } 186 187 // ------------------------------------------------------------------------ 188 // Implementation of the MethodVisitor interface 189 // ------------------------------------------------------------------------ 190 191 public AnnotationVisitor visitAnnotationDefault() { 192 return new AnnotationNode(new ArrayList(0) { 193 public boolean add(final Object o) { 194 annotationDefault = o; 195 return super.add(o); 196 } 197 }); 198 } 199 200 public AnnotationVisitor visitParameterAnnotation( 201 final int parameter, 202 final String desc, 203 final boolean visible) 204 { 205 AnnotationNode an = new AnnotationNode(desc); 206 if (visible) { 207 if (visibleParameterAnnotations == null) { 208 int params = Type.getArgumentTypes(this.desc).length; 209 visibleParameterAnnotations = new List[params]; 210 } 211 if (visibleParameterAnnotations[parameter] == null) { 212 visibleParameterAnnotations[parameter] = new ArrayList(1); 213 } 214 visibleParameterAnnotations[parameter].add(an); 215 } else { 216 if (invisibleParameterAnnotations == null) { 217 int params = Type.getArgumentTypes(this.desc).length; 218 invisibleParameterAnnotations = new List[params]; 219 } 220 if (invisibleParameterAnnotations[parameter] == null) { 221 invisibleParameterAnnotations[parameter] = new ArrayList(1); 222 } 223 invisibleParameterAnnotations[parameter].add(an); 224 } 225 return an; 226 } 227 228 public void visitCode() { 229 } 230 231 public void visitFrame( 232 final int type, 233 final int nLocal, 234 final Object[] local, 235 final int nStack, 236 final Object[] stack) 237 { 238 instructions.add(new FrameNode(type, nLocal, local == null 239 ? null 240 : getLabelNodes(local), nStack, stack == null 241 ? null 242 : getLabelNodes(stack))); 243 } 244 245 public void visitInsn(final int opcode) { 246 instructions.add(new InsnNode(opcode)); 247 } 248 249 public void visitIntInsn(final int opcode, final int operand) { 250 instructions.add(new IntInsnNode(opcode, operand)); 251 } 252 253 public void visitVarInsn(final int opcode, final int var) { 254 instructions.add(new VarInsnNode(opcode, var)); 255 } 256 257 public void visitTypeInsn(final int opcode, final String type) { 258 instructions.add(new TypeInsnNode(opcode, type)); 259 } 260 261 public void visitFieldInsn( 262 final int opcode, 263 final String owner, 264 final String name, 265 final String desc) 266 { 267 instructions.add(new FieldInsnNode(opcode, owner, name, desc)); 268 } 269 270 public void visitMethodInsn( 271 final int opcode, 272 final String owner, 273 final String name, 274 final String desc) 275 { 276 instructions.add(new MethodInsnNode(opcode, owner, name, desc)); 277 } 278 279 public void visitJumpInsn(final int opcode, final Label label) { 280 instructions.add(new JumpInsnNode(opcode, getLabelNode(label))); 281 } 282 283 public void visitLabel(final Label label) { 284 instructions.add(getLabelNode(label)); 285 } 286 287 public void visitLdcInsn(final Object cst) { 288 instructions.add(new LdcInsnNode(cst)); 289 } 290 291 public void visitIincInsn(final int var, final int increment) { 292 instructions.add(new IincInsnNode(var, increment)); 293 } 294 295 public void visitTableSwitchInsn( 296 final int min, 297 final int max, 298 final Label dflt, 299 final Label[] labels) 300 { 301 instructions.add(new TableSwitchInsnNode(min, 302 max, 303 getLabelNode(dflt), 304 getLabelNodes(labels))); 305 } 306 307 public void visitLookupSwitchInsn( 308 final Label dflt, 309 final int[] keys, 310 final Label[] labels) 311 { 312 instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), 313 keys, 314 getLabelNodes(labels))); 315 } 316 317 public void visitMultiANewArrayInsn(final String desc, final int dims) { 318 instructions.add(new MultiANewArrayInsnNode(desc, dims)); 319 } 320 321 public void visitTryCatchBlock( 322 final Label start, 323 final Label end, 324 final Label handler, 325 final String type) 326 { 327 tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start), 328 getLabelNode(end), 329 getLabelNode(handler), 330 type)); 331 } 332 333 public void visitLocalVariable( 334 final String name, 335 final String desc, 336 final String signature, 337 final Label start, 338 final Label end, 339 final int index) 340 { 341 localVariables.add(new LocalVariableNode(name, 342 desc, 343 signature, 344 getLabelNode(start), 345 getLabelNode(end), 346 index)); 347 } 348 349 public void visitLineNumber(final int line, final Label start) { 350 instructions.add(new LineNumberNode(line, getLabelNode(start))); 351 } 352 353 public void visitMaxs(final int maxStack, final int maxLocals) { 354 this.maxStack = maxStack; 355 this.maxLocals = maxLocals; 356 } 357 358 /** 359 * Returns the LabelNode corresponding to the given Label. Creates a new 360 * LabelNode if necessary. The default implementation of this method uses 361 * the {@link Label#info} field to store associations between labels and 362 * label nodes. 363 * 364 * @param l a Label. 365 * @return the LabelNode corresponding to l. 366 */ 367 protected LabelNode getLabelNode(final Label l) { 368 if (!(l.info instanceof LabelNode)) { 369 l.info = new LabelNode(l); 370 } 371 return (LabelNode) l.info; 372 } 373 374 private LabelNode[] getLabelNodes(final Label[] l) { 375 LabelNode[] nodes = new LabelNode[l.length]; 376 for (int i = 0; i < l.length; ++i) { 377 nodes[i] = getLabelNode(l[i]); 378 } 379 return nodes; 380 } 381 382 private Object[] getLabelNodes(final Object[] objs) { 383 Object[] nodes = new Object[objs.length]; 384 for (int i = 0; i < objs.length; ++i) { 385 Object o = objs[i]; 386 if (o instanceof Label) { 387 o = getLabelNode((Label) o); 388 } 389 nodes[i] = o; 390 } 391 return nodes; 392 } 393 394 // ------------------------------------------------------------------------ 395 // Accept method 396 // ------------------------------------------------------------------------ 397 398 /** 399 * Makes the given class visitor visit this method. 400 * 401 * @param cv a class visitor. 402 */ 403 public void accept(final ClassVisitor cv) { 404 String[] exceptions = new String[this.exceptions.size()]; 405 this.exceptions.toArray(exceptions); 406 MethodVisitor mv = cv.visitMethod(access, 407 name, 408 desc, 409 signature, 410 exceptions); 411 if (mv != null) { 412 accept(mv); 413 } 414 } 415 416 /** 417 * Makes the given method visitor visit this method. 418 * 419 * @param mv a method visitor. 420 */ 421 public void accept(final MethodVisitor mv) { 422 // visits the method attributes 423 int i, j, n; 424 if (annotationDefault != null) { 425 AnnotationVisitor av = mv.visitAnnotationDefault(); 426 AnnotationNode.accept(av, null, annotationDefault); 427 if (av != null) { 428 av.visitEnd(); 429 } 430 } 431 n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); 432 for (i = 0; i < n; ++i) { 433 AnnotationNode an = (AnnotationNode) visibleAnnotations.get(i); 434 an.accept(mv.visitAnnotation(an.desc, true)); 435 } 436 n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); 437 for (i = 0; i < n; ++i) { 438 AnnotationNode an = (AnnotationNode) invisibleAnnotations.get(i); 439 an.accept(mv.visitAnnotation(an.desc, false)); 440 } 441 n = visibleParameterAnnotations == null 442 ? 0 443 : visibleParameterAnnotations.length; 444 for (i = 0; i < n; ++i) { 445 List l = visibleParameterAnnotations[i]; 446 if (l == null) { 447 continue; 448 } 449 for (j = 0; j < l.size(); ++j) { 450 AnnotationNode an = (AnnotationNode) l.get(j); 451 an.accept(mv.visitParameterAnnotation(i, an.desc, true)); 452 } 453 } 454 n = invisibleParameterAnnotations == null 455 ? 0 456 : invisibleParameterAnnotations.length; 457 for (i = 0; i < n; ++i) { 458 List l = invisibleParameterAnnotations[i]; 459 if (l == null) { 460 continue; 461 } 462 for (j = 0; j < l.size(); ++j) { 463 AnnotationNode an = (AnnotationNode) l.get(j); 464 an.accept(mv.visitParameterAnnotation(i, an.desc, false)); 465 } 466 } 467 n = attrs == null ? 0 : attrs.size(); 468 for (i = 0; i < n; ++i) { 469 mv.visitAttribute((Attribute) attrs.get(i)); 470 } 471 // visits the method's code 472 if (instructions.size() > 0) { 473 mv.visitCode(); 474 // visits try catch blocks 475 for (i = 0; i < tryCatchBlocks.size(); ++i) { 476 ((TryCatchBlockNode) tryCatchBlocks.get(i)).accept(mv); 477 } 478 // visits instructions 479 instructions.accept(mv); 480 // visits local variables 481 n = localVariables == null ? 0 : localVariables.size(); 482 for (i = 0; i < n; ++i) { 483 ((LocalVariableNode) localVariables.get(i)).accept(mv); 484 } 485 // visits maxs 486 mv.visitMaxs(maxStack, maxLocals); 487 } 488 mv.visitEnd(); 489 } 490} 491