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