001/***
002 * ASM: a very small and fast Java bytecode manipulation framework
003 * Copyright (c) 2000-2011 INRIA, France Telecom
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 * 1. Redistributions of source code must retain the above copyright
010 *    notice, this list of conditions and the following disclaimer.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 *    notice, this list of conditions and the following disclaimer in the
013 *    documentation and/or other materials provided with the distribution.
014 * 3. Neither the name of the copyright holders nor the names of its
015 *    contributors may be used to endorse or promote products derived from
016 *    this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028 * THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package io.ebean.enhance.asm.tree;
031
032import io.ebean.enhance.asm.AnnotationVisitor;
033import io.ebean.enhance.asm.Attribute;
034import io.ebean.enhance.asm.ClassVisitor;
035import io.ebean.enhance.asm.Handle;
036import io.ebean.enhance.asm.Label;
037import io.ebean.enhance.asm.MethodVisitor;
038import io.ebean.enhance.asm.Opcodes;
039import io.ebean.enhance.asm.Type;
040import io.ebean.enhance.asm.TypePath;
041
042import java.util.ArrayList;
043import java.util.Arrays;
044import java.util.List;
045
046/**
047 * A node that represents a method.
048 * 
049 * @author Eric Bruneton
050 */
051public class MethodNode extends MethodVisitor {
052
053    /**
054     * The method's access flags (see {@link Opcodes}). This field also
055     * indicates if the method is synthetic and/or deprecated.
056     */
057    public int access;
058
059    /**
060     * The method's name.
061     */
062    public String name;
063
064    /**
065     * The method's descriptor (see {@link Type}).
066     */
067    public String desc;
068
069    /**
070     * The method's signature. May be <tt>null</tt>.
071     */
072    public String signature;
073
074    /**
075     * The internal names of the method's exception classes (see
076     * {@link Type#getInternalName() getInternalName}). This list is a list of
077     * {@link String} objects.
078     */
079    public List<String> exceptions;
080
081    /**
082     * The method parameter info (access flags and name)
083     */
084    public List<ParameterNode> parameters;
085
086    /**
087     * The runtime visible annotations of this method. This list is a list of
088     * {@link AnnotationNode} objects. May be <tt>null</tt>.
089     * 
090     * @associates org.objectweb.asm.tree.AnnotationNode
091     * @label visible
092     */
093    public List<AnnotationNode> visibleAnnotations;
094
095    /**
096     * The runtime invisible annotations of this method. This list is a list of
097     * {@link AnnotationNode} objects. May be <tt>null</tt>.
098     * 
099     * @associates org.objectweb.asm.tree.AnnotationNode
100     * @label invisible
101     */
102    public List<AnnotationNode> invisibleAnnotations;
103
104    /**
105     * The runtime visible type annotations of this method. This list is a list
106     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
107     * 
108     * @associates org.objectweb.asm.tree.TypeAnnotationNode
109     * @label visible
110     */
111    public List<TypeAnnotationNode> visibleTypeAnnotations;
112
113    /**
114     * The runtime invisible type annotations of this method. This list is a
115     * list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
116     * 
117     * @associates org.objectweb.asm.tree.TypeAnnotationNode
118     * @label invisible
119     */
120    public List<TypeAnnotationNode> invisibleTypeAnnotations;
121
122    /**
123     * The non standard attributes of this method. This list is a list of
124     * {@link Attribute} objects. May be <tt>null</tt>.
125     * 
126     * @associates org.objectweb.asm.Attribute
127     */
128    public List<Attribute> attrs;
129
130    /**
131     * The default value of this annotation interface method. This field must be
132     * a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short},
133     * {@link Integer}, {@link Long}, {@link Float}, {@link Double},
134     * {@link String} or {@link Type}, or an two elements String array (for
135     * enumeration values), a {@link AnnotationNode}, or a {@link List} of
136     * values of one of the preceding types. May be <tt>null</tt>.
137     */
138    public Object annotationDefault;
139
140    /**
141     * The runtime visible parameter annotations of this method. These lists are
142     * lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
143     * 
144     * @associates org.objectweb.asm.tree.AnnotationNode
145     * @label invisible parameters
146     */
147    public List<AnnotationNode>[] visibleParameterAnnotations;
148
149    /**
150     * The runtime invisible parameter annotations of this method. These lists
151     * are lists of {@link AnnotationNode} objects. May be <tt>null</tt>.
152     * 
153     * @associates org.objectweb.asm.tree.AnnotationNode
154     * @label visible parameters
155     */
156    public List<AnnotationNode>[] invisibleParameterAnnotations;
157
158    /**
159     * The instructions of this method. This list is a list of
160     * {@link AbstractInsnNode} objects.
161     * 
162     * @associates org.objectweb.asm.tree.AbstractInsnNode
163     * @label instructions
164     */
165    public InsnList instructions;
166
167    /**
168     * The try catch blocks of this method. This list is a list of
169     * {@link TryCatchBlockNode} objects.
170     * 
171     * @associates org.objectweb.asm.tree.TryCatchBlockNode
172     */
173    public List<TryCatchBlockNode> tryCatchBlocks;
174
175    /**
176     * The maximum stack size of this method.
177     */
178    public int maxStack;
179
180    /**
181     * The maximum number of local variables of this method.
182     */
183    public int maxLocals;
184
185    /**
186     * The local variables of this method. This list is a list of
187     * {@link LocalVariableNode} objects. May be <tt>null</tt>
188     * 
189     * @associates org.objectweb.asm.tree.LocalVariableNode
190     */
191    public List<LocalVariableNode> localVariables;
192
193    /**
194     * The visible local variable annotations of this method. This list is a
195     * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
196     * 
197     * @associates org.objectweb.asm.tree.LocalVariableAnnotationNode
198     */
199    public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
200
201    /**
202     * The invisible local variable annotations of this method. This list is a
203     * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
204     * 
205     * @associates org.objectweb.asm.tree.LocalVariableAnnotationNode
206     */
207    public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
208
209    /**
210     * If the accept method has been called on this object.
211     */
212    private boolean visited;
213
214    /**
215     * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
216     * use this constructor</i>. Instead, they must use the
217     * {@link #MethodNode(int)} version.
218     * 
219     * @throws IllegalStateException
220     *             If a subclass calls this constructor.
221     */
222    public MethodNode() {
223        this(Opcodes.ASM6);
224        if (getClass() != MethodNode.class) {
225            throw new IllegalStateException();
226        }
227    }
228
229    /**
230     * Constructs an uninitialized {@link MethodNode}.
231     * 
232     * @param api
233     *            the ASM API version implemented by this visitor. Must be one
234     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
235     */
236    public MethodNode(final int api) {
237        super(api);
238        this.instructions = new InsnList();
239    }
240
241    /**
242     * Constructs a new {@link MethodNode}. <i>Subclasses must not use this
243     * constructor</i>. Instead, they must use the
244     * {@link #MethodNode(int, int, String, String, String, String[])} version.
245     * 
246     * @param access
247     *            the method's access flags (see {@link Opcodes}). This
248     *            parameter also indicates if the method is synthetic and/or
249     *            deprecated.
250     * @param name
251     *            the method's name.
252     * @param desc
253     *            the method's descriptor (see {@link Type}).
254     * @param signature
255     *            the method's signature. May be <tt>null</tt>.
256     * @param exceptions
257     *            the internal names of the method's exception classes (see
258     *            {@link Type#getInternalName() getInternalName}). May be
259     *            <tt>null</tt>.
260     * @throws IllegalStateException
261     *             If a subclass calls this constructor.
262     */
263    public MethodNode(final int access, final String name, final String desc,
264            final String signature, final String[] exceptions) {
265        this(Opcodes.ASM6, access, name, desc, signature, exceptions);
266        if (getClass() != MethodNode.class) {
267            throw new IllegalStateException();
268        }
269    }
270
271    /**
272     * Constructs a new {@link MethodNode}.
273     * 
274     * @param api
275     *            the ASM API version implemented by this visitor. Must be one
276     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
277     * @param access
278     *            the method's access flags (see {@link Opcodes}). This
279     *            parameter also indicates if the method is synthetic and/or
280     *            deprecated.
281     * @param name
282     *            the method's name.
283     * @param desc
284     *            the method's descriptor (see {@link Type}).
285     * @param signature
286     *            the method's signature. May be <tt>null</tt>.
287     * @param exceptions
288     *            the internal names of the method's exception classes (see
289     *            {@link Type#getInternalName() getInternalName}). May be
290     *            <tt>null</tt>.
291     */
292    public MethodNode(final int api, final int access, final String name,
293            final String desc, final String signature, final String[] exceptions) {
294        super(api);
295        this.access = access;
296        this.name = name;
297        this.desc = desc;
298        this.signature = signature;
299        this.exceptions = new ArrayList<String>(exceptions == null ? 0
300                : exceptions.length);
301        boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0;
302        if (!isAbstract) {
303            this.localVariables = new ArrayList<LocalVariableNode>(5);
304        }
305        this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
306        if (exceptions != null) {
307            this.exceptions.addAll(Arrays.asList(exceptions));
308        }
309        this.instructions = new InsnList();
310    }
311
312    // ------------------------------------------------------------------------
313    // Implementation of the MethodVisitor abstract class
314    // ------------------------------------------------------------------------
315
316    @Override
317    public void visitParameter(String name, int access) {
318        if (parameters == null) {
319            parameters = new ArrayList<ParameterNode>(5);
320        }
321        parameters.add(new ParameterNode(name, access));
322    }
323
324    @Override
325    @SuppressWarnings("serial")
326    public AnnotationVisitor visitAnnotationDefault() {
327        return new AnnotationNode(new ArrayList<Object>(0) {
328            @Override
329            public boolean add(final Object o) {
330                annotationDefault = o;
331                return super.add(o);
332            }
333        });
334    }
335
336    @Override
337    public AnnotationVisitor visitAnnotation(final String desc,
338                                             final boolean visible) {
339        AnnotationNode an = new AnnotationNode(desc);
340        if (visible) {
341            if (visibleAnnotations == null) {
342                visibleAnnotations = new ArrayList<AnnotationNode>(1);
343            }
344            visibleAnnotations.add(an);
345        } else {
346            if (invisibleAnnotations == null) {
347                invisibleAnnotations = new ArrayList<AnnotationNode>(1);
348            }
349            invisibleAnnotations.add(an);
350        }
351        return an;
352    }
353
354    @Override
355    public AnnotationVisitor visitTypeAnnotation(int typeRef,
356                                                 TypePath typePath, String desc, boolean visible) {
357        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
358        if (visible) {
359            if (visibleTypeAnnotations == null) {
360                visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
361            }
362            visibleTypeAnnotations.add(an);
363        } else {
364            if (invisibleTypeAnnotations == null) {
365                invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
366            }
367            invisibleTypeAnnotations.add(an);
368        }
369        return an;
370    }
371
372    @Override
373    @SuppressWarnings("unchecked")
374    public AnnotationVisitor visitParameterAnnotation(final int parameter,
375                                                      final String desc, final boolean visible) {
376        AnnotationNode an = new AnnotationNode(desc);
377        if (visible) {
378            if (visibleParameterAnnotations == null) {
379                int params = Type.getArgumentTypes(this.desc).length;
380                visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
381            }
382            if (visibleParameterAnnotations[parameter] == null) {
383                visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
384                        1);
385            }
386            visibleParameterAnnotations[parameter].add(an);
387        } else {
388            if (invisibleParameterAnnotations == null) {
389                int params = Type.getArgumentTypes(this.desc).length;
390                invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
391            }
392            if (invisibleParameterAnnotations[parameter] == null) {
393                invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(
394                        1);
395            }
396            invisibleParameterAnnotations[parameter].add(an);
397        }
398        return an;
399    }
400
401    @Override
402    public void visitAttribute(final Attribute attr) {
403        if (attrs == null) {
404            attrs = new ArrayList<Attribute>(1);
405        }
406        attrs.add(attr);
407    }
408
409    @Override
410    public void visitCode() {
411    }
412
413    @Override
414    public void visitFrame(final int type, final int nLocal,
415            final Object[] local, final int nStack, final Object[] stack) {
416        instructions.add(new FrameNode(type, nLocal, local == null ? null
417                : getLabelNodes(local), nStack, stack == null ? null
418                : getLabelNodes(stack)));
419    }
420
421    @Override
422    public void visitInsn(final int opcode) {
423        instructions.add(new InsnNode(opcode));
424    }
425
426    @Override
427    public void visitIntInsn(final int opcode, final int operand) {
428        instructions.add(new IntInsnNode(opcode, operand));
429    }
430
431    @Override
432    public void visitVarInsn(final int opcode, final int var) {
433        instructions.add(new VarInsnNode(opcode, var));
434    }
435
436    @Override
437    public void visitTypeInsn(final int opcode, final String type) {
438        instructions.add(new TypeInsnNode(opcode, type));
439    }
440
441    @Override
442    public void visitFieldInsn(final int opcode, final String owner,
443            final String name, final String desc) {
444        instructions.add(new FieldInsnNode(opcode, owner, name, desc));
445    }
446
447    @Deprecated
448    @Override
449    public void visitMethodInsn(int opcode, String owner, String name,
450            String desc) {
451        if (api >= Opcodes.ASM5) {
452            super.visitMethodInsn(opcode, owner, name, desc);
453            return;
454        }
455        instructions.add(new MethodInsnNode(opcode, owner, name, desc));
456    }
457
458    @Override
459    public void visitMethodInsn(int opcode, String owner, String name,
460            String desc, boolean itf) {
461        if (api < Opcodes.ASM5) {
462            super.visitMethodInsn(opcode, owner, name, desc, itf);
463            return;
464        }
465        instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
466    }
467
468    @Override
469    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
470            Object... bsmArgs) {
471        instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
472    }
473
474    @Override
475    public void visitJumpInsn(final int opcode, final Label label) {
476        instructions.add(new JumpInsnNode(opcode, getLabelNode(label)));
477    }
478
479    @Override
480    public void visitLabel(final Label label) {
481        instructions.add(getLabelNode(label));
482    }
483
484    @Override
485    public void visitLdcInsn(final Object cst) {
486        instructions.add(new LdcInsnNode(cst));
487    }
488
489    @Override
490    public void visitIincInsn(final int var, final int increment) {
491        instructions.add(new IincInsnNode(var, increment));
492    }
493
494    @Override
495    public void visitTableSwitchInsn(final int min, final int max,
496                                     final Label dflt, final Label... labels) {
497        instructions.add(new TableSwitchInsnNode(min, max, getLabelNode(dflt),
498                getLabelNodes(labels)));
499    }
500
501    @Override
502    public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
503                                      final Label[] labels) {
504        instructions.add(new LookupSwitchInsnNode(getLabelNode(dflt), keys,
505                getLabelNodes(labels)));
506    }
507
508    @Override
509    public void visitMultiANewArrayInsn(final String desc, final int dims) {
510        instructions.add(new MultiANewArrayInsnNode(desc, dims));
511    }
512
513    @Override
514    public AnnotationVisitor visitInsnAnnotation(int typeRef,
515                                                 TypePath typePath, String desc, boolean visible) {
516        // Finds the last real instruction, i.e. the instruction targeted by
517        // this annotation.
518        AbstractInsnNode insn = instructions.getLast();
519        while (insn.getOpcode() == -1) {
520            insn = insn.getPrevious();
521        }
522        // Adds the annotation to this instruction.
523        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
524        if (visible) {
525            if (insn.visibleTypeAnnotations == null) {
526                insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
527                        1);
528            }
529            insn.visibleTypeAnnotations.add(an);
530        } else {
531            if (insn.invisibleTypeAnnotations == null) {
532                insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
533                        1);
534            }
535            insn.invisibleTypeAnnotations.add(an);
536        }
537        return an;
538    }
539
540    @Override
541    public void visitTryCatchBlock(final Label start, final Label end,
542                                   final Label handler, final String type) {
543        tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
544                getLabelNode(end), getLabelNode(handler), type));
545    }
546
547    @Override
548    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
549                                                     TypePath typePath, String desc, boolean visible) {
550        TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
551        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
552        if (visible) {
553            if (tcb.visibleTypeAnnotations == null) {
554                tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
555                        1);
556            }
557            tcb.visibleTypeAnnotations.add(an);
558        } else {
559            if (tcb.invisibleTypeAnnotations == null) {
560                tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
561                        1);
562            }
563            tcb.invisibleTypeAnnotations.add(an);
564        }
565        return an;
566    }
567
568    @Override
569    public void visitLocalVariable(final String name, final String desc,
570                                   final String signature, final Label start, final Label end,
571                                   final int index) {
572        localVariables.add(new LocalVariableNode(name, desc, signature,
573                getLabelNode(start), getLabelNode(end), index));
574    }
575
576    @Override
577    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
578                                                          TypePath typePath, Label[] start, Label[] end, int[] index,
579                                                          String desc, boolean visible) {
580        LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
581                typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
582                index, desc);
583        if (visible) {
584            if (visibleLocalVariableAnnotations == null) {
585                visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
586                        1);
587            }
588            visibleLocalVariableAnnotations.add(an);
589        } else {
590            if (invisibleLocalVariableAnnotations == null) {
591                invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
592                        1);
593            }
594            invisibleLocalVariableAnnotations.add(an);
595        }
596        return an;
597    }
598
599    @Override
600    public void visitLineNumber(final int line, final Label start) {
601        instructions.add(new LineNumberNode(line, getLabelNode(start)));
602    }
603
604    @Override
605    public void visitMaxs(final int maxStack, final int maxLocals) {
606        this.maxStack = maxStack;
607        this.maxLocals = maxLocals;
608    }
609
610    @Override
611    public void visitEnd() {
612    }
613
614    /**
615     * Returns the LabelNode corresponding to the given Label. Creates a new
616     * LabelNode if necessary. The default implementation of this method uses
617     * the {@link Label#info} field to store associations between labels and
618     * label nodes.
619     * 
620     * @param l
621     *            a Label.
622     * @return the LabelNode corresponding to l.
623     */
624    protected LabelNode getLabelNode(final Label l) {
625        if (!(l.info instanceof LabelNode)) {
626            l.info = new LabelNode();
627        }
628        return (LabelNode) l.info;
629    }
630
631    private LabelNode[] getLabelNodes(final Label[] l) {
632        LabelNode[] nodes = new LabelNode[l.length];
633        for (int i = 0; i < l.length; ++i) {
634            nodes[i] = getLabelNode(l[i]);
635        }
636        return nodes;
637    }
638
639    private Object[] getLabelNodes(final Object[] objs) {
640        Object[] nodes = new Object[objs.length];
641        for (int i = 0; i < objs.length; ++i) {
642            Object o = objs[i];
643            if (o instanceof Label) {
644                o = getLabelNode((Label) o);
645            }
646            nodes[i] = o;
647        }
648        return nodes;
649    }
650
651    // ------------------------------------------------------------------------
652    // Accept method
653    // ------------------------------------------------------------------------
654
655    /**
656     * Checks that this method node is compatible with the given ASM API
657     * version. This methods checks that this node, and all its nodes
658     * recursively, do not contain elements that were introduced in more recent
659     * versions of the ASM API than the given version.
660     * 
661     * @param api
662     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
663     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
664     */
665    public void check(final int api) {
666        if (api == Opcodes.ASM4) {
667            if (visibleTypeAnnotations != null
668                    && visibleTypeAnnotations.size() > 0) {
669                throw new RuntimeException();
670            }
671            if (invisibleTypeAnnotations != null
672                    && invisibleTypeAnnotations.size() > 0) {
673                throw new RuntimeException();
674            }
675            int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
676            for (int i = 0; i < n; ++i) {
677                TryCatchBlockNode tcb = tryCatchBlocks.get(i);
678                if (tcb.visibleTypeAnnotations != null
679                        && tcb.visibleTypeAnnotations.size() > 0) {
680                    throw new RuntimeException();
681                }
682                if (tcb.invisibleTypeAnnotations != null
683                        && tcb.invisibleTypeAnnotations.size() > 0) {
684                    throw new RuntimeException();
685                }
686            }
687            for (int i = 0; i < instructions.size(); ++i) {
688                AbstractInsnNode insn = instructions.get(i);
689                if (insn.visibleTypeAnnotations != null
690                        && insn.visibleTypeAnnotations.size() > 0) {
691                    throw new RuntimeException();
692                }
693                if (insn.invisibleTypeAnnotations != null
694                        && insn.invisibleTypeAnnotations.size() > 0) {
695                    throw new RuntimeException();
696                }
697                if (insn instanceof MethodInsnNode) {
698                    boolean itf = ((MethodInsnNode) insn).itf;
699                    if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
700                        throw new RuntimeException();
701                    }
702                }
703            }
704            if (visibleLocalVariableAnnotations != null
705                    && visibleLocalVariableAnnotations.size() > 0) {
706                throw new RuntimeException();
707            }
708            if (invisibleLocalVariableAnnotations != null
709                    && invisibleLocalVariableAnnotations.size() > 0) {
710                throw new RuntimeException();
711            }
712        }
713    }
714
715    /**
716     * Makes the given class visitor visit this method.
717     * 
718     * @param cv
719     *            a class visitor.
720     */
721    public void accept(final ClassVisitor cv) {
722        String[] exceptions = new String[this.exceptions.size()];
723        this.exceptions.toArray(exceptions);
724        MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
725                exceptions);
726        if (mv != null) {
727            accept(mv);
728        }
729    }
730
731    /**
732     * Makes the given method visitor visit this method.
733     * 
734     * @param mv
735     *            a method visitor.
736     */
737    public void accept(final MethodVisitor mv) {
738        // visits the method parameters
739        int i, j, n;
740        n = parameters == null ? 0 : parameters.size();
741        for (i = 0; i < n; i++) {
742            ParameterNode parameter = parameters.get(i);
743            mv.visitParameter(parameter.name, parameter.access);
744        }
745        // visits the method attributes
746        if (annotationDefault != null) {
747            AnnotationVisitor av = mv.visitAnnotationDefault();
748            AnnotationNode.accept(av, null, annotationDefault);
749            if (av != null) {
750                av.visitEnd();
751            }
752        }
753        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
754        for (i = 0; i < n; ++i) {
755            AnnotationNode an = visibleAnnotations.get(i);
756            an.accept(mv.visitAnnotation(an.desc, true));
757        }
758        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
759        for (i = 0; i < n; ++i) {
760            AnnotationNode an = invisibleAnnotations.get(i);
761            an.accept(mv.visitAnnotation(an.desc, false));
762        }
763        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
764        for (i = 0; i < n; ++i) {
765            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
766            an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
767                    true));
768        }
769        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
770                .size();
771        for (i = 0; i < n; ++i) {
772            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
773            an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
774                    false));
775        }
776        n = visibleParameterAnnotations == null ? 0
777                : visibleParameterAnnotations.length;
778        for (i = 0; i < n; ++i) {
779            List<?> l = visibleParameterAnnotations[i];
780            if (l == null) {
781                continue;
782            }
783            for (j = 0; j < l.size(); ++j) {
784                AnnotationNode an = (AnnotationNode) l.get(j);
785                an.accept(mv.visitParameterAnnotation(i, an.desc, true));
786            }
787        }
788        n = invisibleParameterAnnotations == null ? 0
789                : invisibleParameterAnnotations.length;
790        for (i = 0; i < n; ++i) {
791            List<?> l = invisibleParameterAnnotations[i];
792            if (l == null) {
793                continue;
794            }
795            for (j = 0; j < l.size(); ++j) {
796                AnnotationNode an = (AnnotationNode) l.get(j);
797                an.accept(mv.visitParameterAnnotation(i, an.desc, false));
798            }
799        }
800        if (visited) {
801            instructions.resetLabels();
802        }
803        n = attrs == null ? 0 : attrs.size();
804        for (i = 0; i < n; ++i) {
805            mv.visitAttribute(attrs.get(i));
806        }
807        // visits the method's code
808        if (instructions.size() > 0) {
809            mv.visitCode();
810            // visits try catch blocks
811            n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
812            for (i = 0; i < n; ++i) {
813                tryCatchBlocks.get(i).updateIndex(i);
814                tryCatchBlocks.get(i).accept(mv);
815            }
816            // visits instructions
817            instructions.accept(mv);
818            // visits local variables
819            n = localVariables == null ? 0 : localVariables.size();
820            for (i = 0; i < n; ++i) {
821                localVariables.get(i).accept(mv);
822            }
823            // visits local variable annotations
824            n = visibleLocalVariableAnnotations == null ? 0
825                    : visibleLocalVariableAnnotations.size();
826            for (i = 0; i < n; ++i) {
827                visibleLocalVariableAnnotations.get(i).accept(mv, true);
828            }
829            n = invisibleLocalVariableAnnotations == null ? 0
830                    : invisibleLocalVariableAnnotations.size();
831            for (i = 0; i < n; ++i) {
832                invisibleLocalVariableAnnotations.get(i).accept(mv, false);
833            }
834            // visits maxs
835            mv.visitMaxs(maxStack, maxLocals);
836            visited = true;
837        }
838        mv.visitEnd();
839    }
840}