• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm.tree;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 import org.objectweb.asm.AnnotationVisitor;
33 import org.objectweb.asm.Attribute;
34 import org.objectweb.asm.ClassVisitor;
35 import org.objectweb.asm.FieldVisitor;
36 import org.objectweb.asm.MethodVisitor;
37 import org.objectweb.asm.ModuleVisitor;
38 import org.objectweb.asm.Opcodes;
39 import org.objectweb.asm.RecordComponentVisitor;
40 import org.objectweb.asm.TypePath;
41 
42 /**
43  * A node that represents a class.
44  *
45  * @author Eric Bruneton
46  */
47 public class ClassNode extends ClassVisitor {
48 
49   /**
50    * The class version. The minor version is stored in the 16 most significant bits, and the major
51    * version in the 16 least significant bits.
52    */
53   public int version;
54 
55   /**
56    * The class's access flags (see {@link org.objectweb.asm.Opcodes}). This field also indicates if
57    * the class is deprecated {@link Opcodes#ACC_DEPRECATED} or a record {@link Opcodes#ACC_RECORD}.
58    */
59   public int access;
60 
61   /** The internal name of this class (see {@link org.objectweb.asm.Type#getInternalName()}). */
62   public String name;
63 
64   /** The signature of this class. May be {@literal null}. */
65   public String signature;
66 
67   /**
68    * The internal of name of the super class (see {@link org.objectweb.asm.Type#getInternalName()}).
69    * For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
70    * {@link Object} class.
71    */
72   public String superName;
73 
74   /**
75    * The internal names of the interfaces directly implemented by this class (see {@link
76    * org.objectweb.asm.Type#getInternalName()}).
77    */
78   public List<String> interfaces;
79 
80   /** The name of the source file from which this class was compiled. May be {@literal null}. */
81   public String sourceFile;
82 
83   /**
84    * The correspondence between source and compiled elements of this class. May be {@literal null}.
85    */
86   public String sourceDebug;
87 
88   /** The module stored in this class. May be {@literal null}. */
89   public ModuleNode module;
90 
91   /**
92    * The internal name of the enclosing class of this class (see {@link
93    * org.objectweb.asm.Type#getInternalName()}). Must be {@literal null} if this class has no
94    * enclosing class, or if it is a local or anonymous class.
95    */
96   public String outerClass;
97 
98   /**
99    * The name of the method that contains the class, or {@literal null} if the class has no
100    * enclosing class, or is not enclosed in a method or constructor of its enclosing class (e.g. if
101    * it is enclosed in an instance initializer, static initializer, instance variable initializer,
102    * or class variable initializer).
103    */
104   public String outerMethod;
105 
106   /**
107    * The descriptor of the method that contains the class, or {@literal null} if the class has no
108    * enclosing class, or is not enclosed in a method or constructor of its enclosing class (e.g. if
109    * it is enclosed in an instance initializer, static initializer, instance variable initializer,
110    * or class variable initializer).
111    */
112   public String outerMethodDesc;
113 
114   /** The runtime visible annotations of this class. May be {@literal null}. */
115   public List<AnnotationNode> visibleAnnotations;
116 
117   /** The runtime invisible annotations of this class. May be {@literal null}. */
118   public List<AnnotationNode> invisibleAnnotations;
119 
120   /** The runtime visible type annotations of this class. May be {@literal null}. */
121   public List<TypeAnnotationNode> visibleTypeAnnotations;
122 
123   /** The runtime invisible type annotations of this class. May be {@literal null}. */
124   public List<TypeAnnotationNode> invisibleTypeAnnotations;
125 
126   /** The non standard attributes of this class. May be {@literal null}. */
127   public List<Attribute> attrs;
128 
129   /** The inner classes of this class. */
130   public List<InnerClassNode> innerClasses;
131 
132   /**
133    * The internal name of the nest host class of this class (see {@link
134    * org.objectweb.asm.Type#getInternalName()}). May be {@literal null}.
135    */
136   public String nestHostClass;
137 
138   /**
139    * The internal names of the nest members of this class (see {@link
140    * org.objectweb.asm.Type#getInternalName()}). May be {@literal null}.
141    */
142   public List<String> nestMembers;
143 
144   /**
145    * The internal names of the permitted subclasses of this class (see {@link
146    * org.objectweb.asm.Type#getInternalName()}). May be {@literal null}.
147    */
148   public List<String> permittedSubclasses;
149 
150   /** The record components of this class. May be {@literal null}. */
151   public List<RecordComponentNode> recordComponents;
152 
153   /** The fields of this class. */
154   public List<FieldNode> fields;
155 
156   /** The methods of this class. */
157   public List<MethodNode> methods;
158 
159   /**
160    * Constructs a new {@link ClassNode}. <i>Subclasses must not use this constructor</i>. Instead,
161    * they must use the {@link #ClassNode(int)} version.
162    *
163    * @throws IllegalStateException If a subclass calls this constructor.
164    */
ClassNode()165   public ClassNode() {
166     this(Opcodes.ASM9);
167     if (getClass() != ClassNode.class) {
168       throw new IllegalStateException();
169     }
170   }
171 
172   /**
173    * Constructs a new {@link ClassNode}.
174    *
175    * @param api the ASM API version implemented by this visitor. Must be one of the {@code
176    *     ASM}<i>x</i> values in {@link Opcodes}.
177    */
ClassNode(final int api)178   public ClassNode(final int api) {
179     super(api);
180     this.interfaces = new ArrayList<>();
181     this.innerClasses = new ArrayList<>();
182     this.fields = new ArrayList<>();
183     this.methods = new ArrayList<>();
184   }
185 
186   // -----------------------------------------------------------------------------------------------
187   // Implementation of the ClassVisitor abstract class
188   // -----------------------------------------------------------------------------------------------
189 
190   @Override
visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)191   public void visit(
192       final int version,
193       final int access,
194       final String name,
195       final String signature,
196       final String superName,
197       final String[] interfaces) {
198     this.version = version;
199     this.access = access;
200     this.name = name;
201     this.signature = signature;
202     this.superName = superName;
203     this.interfaces = Util.asArrayList(interfaces);
204   }
205 
206   @Override
visitSource(final String file, final String debug)207   public void visitSource(final String file, final String debug) {
208     sourceFile = file;
209     sourceDebug = debug;
210   }
211 
212   @Override
visitModule(final String name, final int access, final String version)213   public ModuleVisitor visitModule(final String name, final int access, final String version) {
214     module = new ModuleNode(name, access, version);
215     return module;
216   }
217 
218   @Override
visitNestHost(final String nestHost)219   public void visitNestHost(final String nestHost) {
220     this.nestHostClass = nestHost;
221   }
222 
223   @Override
visitOuterClass(final String owner, final String name, final String descriptor)224   public void visitOuterClass(final String owner, final String name, final String descriptor) {
225     outerClass = owner;
226     outerMethod = name;
227     outerMethodDesc = descriptor;
228   }
229 
230   @Override
visitAnnotation(final String descriptor, final boolean visible)231   public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
232     AnnotationNode annotation = new AnnotationNode(descriptor);
233     if (visible) {
234       visibleAnnotations = Util.add(visibleAnnotations, annotation);
235     } else {
236       invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
237     }
238     return annotation;
239   }
240 
241   @Override
visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)242   public AnnotationVisitor visitTypeAnnotation(
243       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
244     TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
245     if (visible) {
246       visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
247     } else {
248       invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
249     }
250     return typeAnnotation;
251   }
252 
253   @Override
visitAttribute(final Attribute attribute)254   public void visitAttribute(final Attribute attribute) {
255     attrs = Util.add(attrs, attribute);
256   }
257 
258   @Override
visitNestMember(final String nestMember)259   public void visitNestMember(final String nestMember) {
260     nestMembers = Util.add(nestMembers, nestMember);
261   }
262 
263   @Override
visitPermittedSubclass(final String permittedSubclass)264   public void visitPermittedSubclass(final String permittedSubclass) {
265     permittedSubclasses = Util.add(permittedSubclasses, permittedSubclass);
266   }
267 
268   @Override
visitInnerClass( final String name, final String outerName, final String innerName, final int access)269   public void visitInnerClass(
270       final String name, final String outerName, final String innerName, final int access) {
271     InnerClassNode innerClass = new InnerClassNode(name, outerName, innerName, access);
272     innerClasses.add(innerClass);
273   }
274 
275   @Override
visitRecordComponent( final String name, final String descriptor, final String signature)276   public RecordComponentVisitor visitRecordComponent(
277       final String name, final String descriptor, final String signature) {
278     RecordComponentNode recordComponent = new RecordComponentNode(name, descriptor, signature);
279     recordComponents = Util.add(recordComponents, recordComponent);
280     return recordComponent;
281   }
282 
283   @Override
visitField( final int access, final String name, final String descriptor, final String signature, final Object value)284   public FieldVisitor visitField(
285       final int access,
286       final String name,
287       final String descriptor,
288       final String signature,
289       final Object value) {
290     FieldNode field = new FieldNode(access, name, descriptor, signature, value);
291     fields.add(field);
292     return field;
293   }
294 
295   @Override
visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)296   public MethodVisitor visitMethod(
297       final int access,
298       final String name,
299       final String descriptor,
300       final String signature,
301       final String[] exceptions) {
302     MethodNode method = new MethodNode(access, name, descriptor, signature, exceptions);
303     methods.add(method);
304     return method;
305   }
306 
307   @Override
visitEnd()308   public void visitEnd() {
309     // Nothing to do.
310   }
311 
312   // -----------------------------------------------------------------------------------------------
313   // Accept method
314   // -----------------------------------------------------------------------------------------------
315 
316   /**
317    * Checks that this class node is compatible with the given ASM API version. This method checks
318    * that this node, and all its children recursively, do not contain elements that were introduced
319    * in more recent versions of the ASM API than the given version.
320    *
321    * @param api an ASM API version. Must be one of the {@code ASM}<i>x</i> values in {@link
322    *     Opcodes}.
323    */
check(final int api)324   public void check(final int api) {
325     if (api < Opcodes.ASM9 && permittedSubclasses != null) {
326       throw new UnsupportedClassVersionException();
327     }
328     if (api < Opcodes.ASM8 && ((access & Opcodes.ACC_RECORD) != 0 || recordComponents != null)) {
329       throw new UnsupportedClassVersionException();
330     }
331     if (api < Opcodes.ASM7 && (nestHostClass != null || nestMembers != null)) {
332       throw new UnsupportedClassVersionException();
333     }
334     if (api < Opcodes.ASM6 && module != null) {
335       throw new UnsupportedClassVersionException();
336     }
337     if (api < Opcodes.ASM5) {
338       if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
339         throw new UnsupportedClassVersionException();
340       }
341       if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
342         throw new UnsupportedClassVersionException();
343       }
344     }
345     // Check the annotations.
346     if (visibleAnnotations != null) {
347       for (int i = visibleAnnotations.size() - 1; i >= 0; --i) {
348         visibleAnnotations.get(i).check(api);
349       }
350     }
351     if (invisibleAnnotations != null) {
352       for (int i = invisibleAnnotations.size() - 1; i >= 0; --i) {
353         invisibleAnnotations.get(i).check(api);
354       }
355     }
356     if (visibleTypeAnnotations != null) {
357       for (int i = visibleTypeAnnotations.size() - 1; i >= 0; --i) {
358         visibleTypeAnnotations.get(i).check(api);
359       }
360     }
361     if (invisibleTypeAnnotations != null) {
362       for (int i = invisibleTypeAnnotations.size() - 1; i >= 0; --i) {
363         invisibleTypeAnnotations.get(i).check(api);
364       }
365     }
366     if (recordComponents != null) {
367       for (int i = recordComponents.size() - 1; i >= 0; --i) {
368         recordComponents.get(i).check(api);
369       }
370     }
371     for (int i = fields.size() - 1; i >= 0; --i) {
372       fields.get(i).check(api);
373     }
374     for (int i = methods.size() - 1; i >= 0; --i) {
375       methods.get(i).check(api);
376     }
377   }
378 
379   /**
380    * Makes the given class visitor visit this class.
381    *
382    * @param classVisitor a class visitor.
383    */
accept(final ClassVisitor classVisitor)384   public void accept(final ClassVisitor classVisitor) {
385     // Visit the header.
386     String[] interfacesArray = new String[this.interfaces.size()];
387     this.interfaces.toArray(interfacesArray);
388     classVisitor.visit(version, access, name, signature, superName, interfacesArray);
389     // Visit the source.
390     if (sourceFile != null || sourceDebug != null) {
391       classVisitor.visitSource(sourceFile, sourceDebug);
392     }
393     // Visit the module.
394     if (module != null) {
395       module.accept(classVisitor);
396     }
397     // Visit the nest host class.
398     if (nestHostClass != null) {
399       classVisitor.visitNestHost(nestHostClass);
400     }
401     // Visit the outer class.
402     if (outerClass != null) {
403       classVisitor.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
404     }
405     // Visit the annotations.
406     if (visibleAnnotations != null) {
407       for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
408         AnnotationNode annotation = visibleAnnotations.get(i);
409         annotation.accept(classVisitor.visitAnnotation(annotation.desc, true));
410       }
411     }
412     if (invisibleAnnotations != null) {
413       for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
414         AnnotationNode annotation = invisibleAnnotations.get(i);
415         annotation.accept(classVisitor.visitAnnotation(annotation.desc, false));
416       }
417     }
418     if (visibleTypeAnnotations != null) {
419       for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
420         TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
421         typeAnnotation.accept(
422             classVisitor.visitTypeAnnotation(
423                 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
424       }
425     }
426     if (invisibleTypeAnnotations != null) {
427       for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
428         TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
429         typeAnnotation.accept(
430             classVisitor.visitTypeAnnotation(
431                 typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
432       }
433     }
434     // Visit the non standard attributes.
435     if (attrs != null) {
436       for (int i = 0, n = attrs.size(); i < n; ++i) {
437         classVisitor.visitAttribute(attrs.get(i));
438       }
439     }
440     // Visit the nest members.
441     if (nestMembers != null) {
442       for (int i = 0, n = nestMembers.size(); i < n; ++i) {
443         classVisitor.visitNestMember(nestMembers.get(i));
444       }
445     }
446     // Visit the permitted subclasses.
447     if (permittedSubclasses != null) {
448       for (int i = 0, n = permittedSubclasses.size(); i < n; ++i) {
449         classVisitor.visitPermittedSubclass(permittedSubclasses.get(i));
450       }
451     }
452     // Visit the inner classes.
453     for (int i = 0, n = innerClasses.size(); i < n; ++i) {
454       innerClasses.get(i).accept(classVisitor);
455     }
456     // Visit the record components.
457     if (recordComponents != null) {
458       for (int i = 0, n = recordComponents.size(); i < n; ++i) {
459         recordComponents.get(i).accept(classVisitor);
460       }
461     }
462     // Visit the fields.
463     for (int i = 0, n = fields.size(); i < n; ++i) {
464       fields.get(i).accept(classVisitor);
465     }
466     // Visit the methods.
467     for (int i = 0, n = methods.size(); i < n; ++i) {
468       methods.get(i).accept(classVisitor);
469     }
470     classVisitor.visitEnd();
471   }
472 }
473