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.FieldVisitor;
036import io.ebean.enhance.asm.MethodVisitor;
037import io.ebean.enhance.asm.ModuleVisitor;
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 class.
048 * 
049 * @author Eric Bruneton
050 */
051public class ClassNode extends ClassVisitor {
052
053    /**
054     * The class version.
055     */
056    public int version;
057
058    /**
059     * The class's access flags (see {@link Opcodes}). This
060     * field also indicates if the class is deprecated.
061     */
062    public int access;
063
064    /**
065     * The internal name of the class (see
066     * {@link Type#getInternalName() getInternalName}).
067     */
068    public String name;
069
070    /**
071     * The signature of the class. May be <tt>null</tt>.
072     */
073    public String signature;
074
075    /**
076     * The internal of name of the super class (see
077     * {@link Type#getInternalName() getInternalName}). For
078     * interfaces, the super class is {@link Object}. May be <tt>null</tt>, but
079     * only for the {@link Object} class.
080     */
081    public String superName;
082
083    /**
084     * The internal names of the class's interfaces (see
085     * {@link Type#getInternalName() getInternalName}). This
086     * list is a list of {@link String} objects.
087     */
088    public List<String> interfaces;
089
090    /**
091     * The name of the source file from which this class was compiled. May be
092     * <tt>null</tt>.
093     */
094    public String sourceFile;
095
096    /**
097     * Debug information to compute the correspondence between source and
098     * compiled elements of the class. May be <tt>null</tt>.
099     */
100    public String sourceDebug;
101
102    /**
103     * Module information. May be <tt>null</tt>.
104     */
105    public ModuleNode module;
106    
107    /**
108     * The internal name of the enclosing class of the class. May be
109     * <tt>null</tt>.
110     */
111    public String outerClass;
112
113    /**
114     * The name of the method that contains the class, or <tt>null</tt> if the
115     * class is not enclosed in a method.
116     */
117    public String outerMethod;
118
119    /**
120     * The descriptor of the method that contains the class, or <tt>null</tt> if
121     * the class is not enclosed in a method.
122     */
123    public String outerMethodDesc;
124
125    /**
126     * The runtime visible annotations of this class. This list is a list of
127     * {@link AnnotationNode} objects. May be <tt>null</tt>.
128     * 
129     * @associates org.objectweb.asm.tree.AnnotationNode
130     * @label visible
131     */
132    public List<AnnotationNode> visibleAnnotations;
133
134    /**
135     * The runtime invisible annotations of this class. This list is a list of
136     * {@link AnnotationNode} objects. May be <tt>null</tt>.
137     * 
138     * @associates org.objectweb.asm.tree.AnnotationNode
139     * @label invisible
140     */
141    public List<AnnotationNode> invisibleAnnotations;
142
143    /**
144     * The runtime visible type annotations of this class. This list is a list
145     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
146     * 
147     * @associates org.objectweb.asm.tree.TypeAnnotationNode
148     * @label visible
149     */
150    public List<TypeAnnotationNode> visibleTypeAnnotations;
151
152    /**
153     * The runtime invisible type annotations of this class. This list is a list
154     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
155     * 
156     * @associates org.objectweb.asm.tree.TypeAnnotationNode
157     * @label invisible
158     */
159    public List<TypeAnnotationNode> invisibleTypeAnnotations;
160
161    /**
162     * The non standard attributes of this class. This list is a list of
163     * {@link Attribute} objects. May be <tt>null</tt>.
164     * 
165     * @associates org.objectweb.asm.Attribute
166     */
167    public List<Attribute> attrs;
168
169    /**
170     * Informations about the inner classes of this class. This list is a list
171     * of {@link InnerClassNode} objects.
172     * 
173     * @associates org.objectweb.asm.tree.InnerClassNode
174     */
175    public List<InnerClassNode> innerClasses;
176
177    /**
178     * The fields of this class. This list is a list of {@link FieldNode}
179     * objects.
180     * 
181     * @associates org.objectweb.asm.tree.FieldNode
182     */
183    public List<FieldNode> fields;
184
185    /**
186     * The methods of this class. This list is a list of {@link MethodNode}
187     * objects.
188     * 
189     * @associates org.objectweb.asm.tree.MethodNode
190     */
191    public List<MethodNode> methods;
192
193    /**
194     * Constructs a new {@link ClassNode}. <i>Subclasses must not use this
195     * constructor</i>. Instead, they must use the {@link #ClassNode(int)}
196     * version.
197     * 
198     * @throws IllegalStateException
199     *             If a subclass calls this constructor.
200     */
201    public ClassNode() {
202        this(Opcodes.ASM6);
203        if (getClass() != ClassNode.class) {
204            throw new IllegalStateException();
205        }
206    }
207
208    /**
209     * Constructs a new {@link ClassNode}.
210     * 
211     * @param api
212     *            the ASM API version implemented by this visitor. Must be one
213     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
214     */
215    public ClassNode(final int api) {
216        super(api);
217        this.interfaces = new ArrayList<String>();
218        this.innerClasses = new ArrayList<InnerClassNode>();
219        this.fields = new ArrayList<FieldNode>();
220        this.methods = new ArrayList<MethodNode>();
221    }
222
223    // ------------------------------------------------------------------------
224    // Implementation of the ClassVisitor abstract class
225    // ------------------------------------------------------------------------
226
227    @Override
228    public void visit(final int version, final int access, final String name,
229            final String signature, final String superName,
230            final String[] interfaces) {
231        this.version = version;
232        this.access = access;
233        this.name = name;
234        this.signature = signature;
235        this.superName = superName;
236        if (interfaces != null) {
237            this.interfaces.addAll(Arrays.asList(interfaces));
238        }
239    }
240
241    @Override
242    public void visitSource(final String file, final String debug) {
243        sourceFile = file;
244        sourceDebug = debug;
245    }
246    
247    @Override
248    public ModuleVisitor visitModule(final String name, final int access,
249                                     final String version) {
250        return module = new ModuleNode(name, access, version); 
251    }
252
253    @Override
254    public void visitOuterClass(final String owner, final String name,
255            final String desc) {
256        outerClass = owner;
257        outerMethod = name;
258        outerMethodDesc = desc;
259    }
260
261    @Override
262    public AnnotationVisitor visitAnnotation(final String desc,
263                                             final boolean visible) {
264        AnnotationNode an = new AnnotationNode(desc);
265        if (visible) {
266            if (visibleAnnotations == null) {
267                visibleAnnotations = new ArrayList<AnnotationNode>(1);
268            }
269            visibleAnnotations.add(an);
270        } else {
271            if (invisibleAnnotations == null) {
272                invisibleAnnotations = new ArrayList<AnnotationNode>(1);
273            }
274            invisibleAnnotations.add(an);
275        }
276        return an;
277    }
278
279    @Override
280    public AnnotationVisitor visitTypeAnnotation(int typeRef,
281                                                 TypePath typePath, String desc, boolean visible) {
282        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
283        if (visible) {
284            if (visibleTypeAnnotations == null) {
285                visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
286            }
287            visibleTypeAnnotations.add(an);
288        } else {
289            if (invisibleTypeAnnotations == null) {
290                invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
291            }
292            invisibleTypeAnnotations.add(an);
293        }
294        return an;
295    }
296
297    @Override
298    public void visitAttribute(final Attribute attr) {
299        if (attrs == null) {
300            attrs = new ArrayList<Attribute>(1);
301        }
302        attrs.add(attr);
303    }
304
305    @Override
306    public void visitInnerClass(final String name, final String outerName,
307            final String innerName, final int access) {
308        InnerClassNode icn = new InnerClassNode(name, outerName, innerName,
309                access);
310        innerClasses.add(icn);
311    }
312
313    @Override
314    public FieldVisitor visitField(final int access, final String name,
315                                   final String desc, final String signature, final Object value) {
316        FieldNode fn = new FieldNode(access, name, desc, signature, value);
317        fields.add(fn);
318        return fn;
319    }
320
321    @Override
322    public MethodVisitor visitMethod(final int access, final String name,
323                                     final String desc, final String signature, final String[] exceptions) {
324        MethodNode mn = new MethodNode(access, name, desc, signature,
325                exceptions);
326        methods.add(mn);
327        return mn;
328    }
329
330    @Override
331    public void visitEnd() {
332    }
333
334    // ------------------------------------------------------------------------
335    // Accept method
336    // ------------------------------------------------------------------------
337
338    /**
339     * Checks that this class node is compatible with the given ASM API version.
340     * This methods checks that this node, and all its nodes recursively, do not
341     * contain elements that were introduced in more recent versions of the ASM
342     * API than the given version.
343     * 
344     * @param api
345     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
346     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
347     */
348    public void check(final int api) {
349        if (api < Opcodes.ASM6) {
350            if (module != null) {
351                throw new RuntimeException();
352            }
353        }
354        if (api < Opcodes.ASM5) {
355            if (visibleTypeAnnotations != null
356                    && visibleTypeAnnotations.size() > 0) {
357                throw new RuntimeException();
358            }
359            if (invisibleTypeAnnotations != null
360                    && invisibleTypeAnnotations.size() > 0) {
361                throw new RuntimeException();
362            }
363        }
364        // checks attributes
365        int i, n;
366        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
367        for (i = 0; i < n; ++i) {
368            visibleAnnotations.get(i).check(api);
369        }
370        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
371        for (i = 0; i < n; ++i) {
372            invisibleAnnotations.get(i).check(api);
373        }
374        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
375        for (i = 0; i < n; ++i) {
376            visibleTypeAnnotations.get(i).check(api);
377        }
378        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
379                .size();
380        for (i = 0; i < n; ++i) {
381            invisibleTypeAnnotations.get(i).check(api);
382        }
383        for (FieldNode f : fields) {
384            f.check(api);
385        }
386        for (MethodNode m : methods) {
387            m.check(api);
388        }
389    }
390
391    /**
392     * Makes the given class visitor visit this class.
393     * 
394     * @param cv
395     *            a class visitor.
396     */
397    public void accept(final ClassVisitor cv) {
398        // visits header
399        String[] interfaces = new String[this.interfaces.size()];
400        this.interfaces.toArray(interfaces);
401        cv.visit(version, access, name, signature, superName, interfaces);
402        // visits source
403        if (sourceFile != null || sourceDebug != null) {
404            cv.visitSource(sourceFile, sourceDebug);
405        }
406        // visits module
407        if (module != null) {
408            module.accept(cv);
409        }
410        // visits outer class
411        if (outerClass != null) {
412            cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
413        }
414        // visits attributes
415        int i, n;
416        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
417        for (i = 0; i < n; ++i) {
418            AnnotationNode an = visibleAnnotations.get(i);
419            an.accept(cv.visitAnnotation(an.desc, true));
420        }
421        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
422        for (i = 0; i < n; ++i) {
423            AnnotationNode an = invisibleAnnotations.get(i);
424            an.accept(cv.visitAnnotation(an.desc, false));
425        }
426        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
427        for (i = 0; i < n; ++i) {
428            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
429            an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
430                    true));
431        }
432        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
433                .size();
434        for (i = 0; i < n; ++i) {
435            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
436            an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
437                    false));
438        }
439        n = attrs == null ? 0 : attrs.size();
440        for (i = 0; i < n; ++i) {
441            cv.visitAttribute(attrs.get(i));
442        }
443        // visits inner classes
444        for (i = 0; i < innerClasses.size(); ++i) {
445            innerClasses.get(i).accept(cv);
446        }
447        // visits fields
448        for (i = 0; i < fields.size(); ++i) {
449            fields.get(i).accept(cv);
450        }
451        // visits methods
452        for (i = 0; i < methods.size(); ++i) {
453            methods.get(i).accept(cv);
454        }
455        // visits end
456        cv.visitEnd();
457    }
458}