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.util; 29 30 import java.io.PrintWriter; 31 import org.objectweb.asm.AnnotationVisitor; 32 import org.objectweb.asm.Attribute; 33 import org.objectweb.asm.ClassVisitor; 34 import org.objectweb.asm.FieldVisitor; 35 import org.objectweb.asm.MethodVisitor; 36 import org.objectweb.asm.ModuleVisitor; 37 import org.objectweb.asm.Opcodes; 38 import org.objectweb.asm.RecordComponentVisitor; 39 import org.objectweb.asm.TypePath; 40 41 /** 42 * A {@link ClassVisitor} that prints the classes it visits with a {@link Printer}. This class 43 * visitor can be used in the middle of a class visitor chain to trace the class that is visited at 44 * a given point in this chain. This may be useful for debugging purposes. 45 * 46 * <p>When used with a {@link Textifier}, the trace printed when visiting the {@code Hello} class is 47 * the following: 48 * 49 * <pre> 50 * // class version 49.0 (49) // access flags 0x21 public class Hello { 51 * 52 * // compiled from: Hello.java 53 * 54 * // access flags 0x1 55 * public <init> ()V 56 * ALOAD 0 57 * INVOKESPECIAL java/lang/Object <init> ()V 58 * RETURN 59 * MAXSTACK = 1 MAXLOCALS = 1 60 * 61 * // access flags 0x9 62 * public static main ([Ljava/lang/String;)V 63 * GETSTATIC java/lang/System out Ljava/io/PrintStream; 64 * LDC "hello" 65 * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V 66 * RETURN 67 * MAXSTACK = 2 MAXLOCALS = 1 68 * } 69 * </pre> 70 * 71 * <p>where {@code Hello} is defined by: 72 * 73 * <pre> 74 * public class Hello { 75 * 76 * public static void main(String[] args) { 77 * System.out.println("hello"); 78 * } 79 * } 80 * </pre> 81 * 82 * @author Eric Bruneton 83 * @author Eugene Kuleshov 84 */ 85 public final class TraceClassVisitor extends ClassVisitor { 86 87 /** The print writer to be used to print the class. May be {@literal null}. */ 88 private final PrintWriter printWriter; 89 90 /** The printer to convert the visited class into text. */ 91 // DontCheck(MemberName): can't be renamed (for backward binary compatibility). 92 public final Printer p; 93 94 /** 95 * Constructs a new {@link TraceClassVisitor}. 96 * 97 * @param printWriter the print writer to be used to print the class. May be {@literal null}. 98 */ TraceClassVisitor(final PrintWriter printWriter)99 public TraceClassVisitor(final PrintWriter printWriter) { 100 this(null, printWriter); 101 } 102 103 /** 104 * Constructs a new {@link TraceClassVisitor}. 105 * 106 * @param classVisitor the class visitor to which to delegate calls. May be {@literal null}. 107 * @param printWriter the print writer to be used to print the class. May be {@literal null}. 108 */ TraceClassVisitor(final ClassVisitor classVisitor, final PrintWriter printWriter)109 public TraceClassVisitor(final ClassVisitor classVisitor, final PrintWriter printWriter) { 110 this(classVisitor, new Textifier(), printWriter); 111 } 112 113 /** 114 * Constructs a new {@link TraceClassVisitor}. 115 * 116 * @param classVisitor the class visitor to which to delegate calls. May be {@literal null}. 117 * @param printer the printer to convert the visited class into text. 118 * @param printWriter the print writer to be used to print the class. May be {@literal null}. 119 */ TraceClassVisitor( final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter)120 public TraceClassVisitor( 121 final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) { 122 super(/* latest api = */ Opcodes.ASM10_EXPERIMENTAL, classVisitor); 123 this.printWriter = printWriter; 124 this.p = printer; 125 } 126 127 @Override visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)128 public void visit( 129 final int version, 130 final int access, 131 final String name, 132 final String signature, 133 final String superName, 134 final String[] interfaces) { 135 p.visit(version, access, name, signature, superName, interfaces); 136 super.visit(version, access, name, signature, superName, interfaces); 137 } 138 139 @Override visitSource(final String file, final String debug)140 public void visitSource(final String file, final String debug) { 141 p.visitSource(file, debug); 142 super.visitSource(file, debug); 143 } 144 145 @Override visitModule(final String name, final int flags, final String version)146 public ModuleVisitor visitModule(final String name, final int flags, final String version) { 147 Printer modulePrinter = p.visitModule(name, flags, version); 148 return new TraceModuleVisitor(super.visitModule(name, flags, version), modulePrinter); 149 } 150 151 @Override visitNestHost(final String nestHost)152 public void visitNestHost(final String nestHost) { 153 p.visitNestHost(nestHost); 154 super.visitNestHost(nestHost); 155 } 156 157 @Override visitOuterClass(final String owner, final String name, final String descriptor)158 public void visitOuterClass(final String owner, final String name, final String descriptor) { 159 p.visitOuterClass(owner, name, descriptor); 160 super.visitOuterClass(owner, name, descriptor); 161 } 162 163 @Override visitAnnotation(final String descriptor, final boolean visible)164 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 165 Printer annotationPrinter = p.visitClassAnnotation(descriptor, visible); 166 return new TraceAnnotationVisitor( 167 super.visitAnnotation(descriptor, visible), annotationPrinter); 168 } 169 170 @Override visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)171 public AnnotationVisitor visitTypeAnnotation( 172 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 173 Printer annotationPrinter = p.visitClassTypeAnnotation(typeRef, typePath, descriptor, visible); 174 return new TraceAnnotationVisitor( 175 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter); 176 } 177 178 @Override visitAttribute(final Attribute attribute)179 public void visitAttribute(final Attribute attribute) { 180 p.visitClassAttribute(attribute); 181 super.visitAttribute(attribute); 182 } 183 184 @Override visitNestMember(final String nestMember)185 public void visitNestMember(final String nestMember) { 186 p.visitNestMember(nestMember); 187 super.visitNestMember(nestMember); 188 } 189 190 @Override visitPermittedSubclass(final String permittedSubclass)191 public void visitPermittedSubclass(final String permittedSubclass) { 192 p.visitPermittedSubclass(permittedSubclass); 193 super.visitPermittedSubclass(permittedSubclass); 194 } 195 196 @Override visitInnerClass( final String name, final String outerName, final String innerName, final int access)197 public void visitInnerClass( 198 final String name, final String outerName, final String innerName, final int access) { 199 p.visitInnerClass(name, outerName, innerName, access); 200 super.visitInnerClass(name, outerName, innerName, access); 201 } 202 203 @Override visitRecordComponent( final String name, final String descriptor, final String signature)204 public RecordComponentVisitor visitRecordComponent( 205 final String name, final String descriptor, final String signature) { 206 Printer recordComponentPrinter = p.visitRecordComponent(name, descriptor, signature); 207 return new TraceRecordComponentVisitor( 208 super.visitRecordComponent(name, descriptor, signature), recordComponentPrinter); 209 } 210 211 @Override visitField( final int access, final String name, final String descriptor, final String signature, final Object value)212 public FieldVisitor visitField( 213 final int access, 214 final String name, 215 final String descriptor, 216 final String signature, 217 final Object value) { 218 Printer fieldPrinter = p.visitField(access, name, descriptor, signature, value); 219 return new TraceFieldVisitor( 220 super.visitField(access, name, descriptor, signature, value), fieldPrinter); 221 } 222 223 @Override visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)224 public MethodVisitor visitMethod( 225 final int access, 226 final String name, 227 final String descriptor, 228 final String signature, 229 final String[] exceptions) { 230 Printer methodPrinter = p.visitMethod(access, name, descriptor, signature, exceptions); 231 return new TraceMethodVisitor( 232 super.visitMethod(access, name, descriptor, signature, exceptions), methodPrinter); 233 } 234 235 @Override visitEnd()236 public void visitEnd() { 237 p.visitClassEnd(); 238 if (printWriter != null) { 239 p.print(printWriter); 240 printWriter.flush(); 241 } 242 super.visitEnd(); 243 } 244 } 245