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