1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.classfile.visitor;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.annotation.*;
26import proguard.classfile.attribute.annotation.visitor.*;
27import proguard.classfile.attribute.preverification.*;
28import proguard.classfile.attribute.preverification.visitor.*;
29import proguard.classfile.attribute.visitor.*;
30import proguard.classfile.constant.*;
31import proguard.classfile.constant.visitor.ConstantVisitor;
32import proguard.classfile.instruction.*;
33import proguard.classfile.instruction.visitor.InstructionVisitor;
34import proguard.classfile.util.*;
35
36import java.io.PrintStream;
37
38
39/**
40 * This <code>ClassVisitor</code> prints out the complete internal
41 * structure of the classes it visits.
42 *
43 * @author Eric Lafortune
44 */
45public class ClassPrinter
46extends      SimplifiedVisitor
47implements   ClassVisitor,
48             ConstantVisitor,
49             MemberVisitor,
50             AttributeVisitor,
51             ExceptionInfoVisitor,
52             InnerClassesInfoVisitor,
53             StackMapFrameVisitor,
54             VerificationTypeVisitor,
55             LineNumberInfoVisitor,
56             LocalVariableInfoVisitor,
57             LocalVariableTypeInfoVisitor,
58             AnnotationVisitor,
59             ElementValueVisitor,
60             InstructionVisitor
61{
62    private static final String INDENTATION = "  ";
63
64    private final PrintStream ps;
65    private int         indentation;
66
67
68    /**
69     * Creates a new ClassPrinter that prints to <code>System.out</code>.
70     */
71    public ClassPrinter()
72    {
73        this(System.out);
74    }
75
76
77    /**
78     * Creates a new ClassPrinter that prints to the given
79     * <code>PrintStream</code>.
80     */
81    public ClassPrinter(PrintStream printStream)
82    {
83        ps = printStream;
84    }
85
86
87    // Implementations for ClassVisitor.
88
89    public void visitProgramClass(ProgramClass programClass)
90    {
91        println("_____________________________________________________________________");
92        println(visitorInfo(programClass) + " " +
93                "Program class: " + programClass.getName());
94        indent();
95        println("Superclass:    " + programClass.getSuperName());
96        println("Major version: 0x" + Integer.toHexString(ClassUtil.internalMajorClassVersion(programClass.u4version)));
97        println("Minor version: 0x" + Integer.toHexString(ClassUtil.internalMinorClassVersion(programClass.u4version)));
98        println("Access flags:  0x" + Integer.toHexString(programClass.u2accessFlags));
99        println("  = " +
100                ((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0 ? "@ " : "") +
101                ClassUtil.externalClassAccessFlags(programClass.u2accessFlags) +
102                ((programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ENUM)      != 0 ? "enum " :
103                 (programClass.u2accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) == 0 ? "class " :
104                                                                                             "") +
105                ClassUtil.externalClassName(programClass.getName()) +
106                (programClass.u2superClass == 0 ? "" : " extends " +
107                ClassUtil.externalClassName(programClass.getSuperName())));
108        outdent();
109        println();
110
111        println("Interfaces (count = " + programClass.u2interfacesCount + "):");
112        indent();
113        programClass.interfaceConstantsAccept(this);
114        outdent();
115        println();
116
117        println("Constant Pool (count = " + programClass.u2constantPoolCount + "):");
118        indent();
119        programClass.constantPoolEntriesAccept(this);
120        outdent();
121        println();
122
123        println("Fields (count = " + programClass.u2fieldsCount + "):");
124        indent();
125        programClass.fieldsAccept(this);
126        outdent();
127        println();
128
129        println("Methods (count = " + programClass.u2methodsCount + "):");
130        indent();
131        programClass.methodsAccept(this);
132        outdent();
133        println();
134
135        println("Class file attributes (count = " + programClass.u2attributesCount + "):");
136        indent();
137        programClass.attributesAccept(this);
138        outdent();
139        println();
140    }
141
142
143    public void visitLibraryClass(LibraryClass libraryClass)
144    {
145        println("_____________________________________________________________________");
146        println(visitorInfo(libraryClass) + " " +
147                "Library class: " + libraryClass.getName());
148        indent();
149        println("Superclass:    " + libraryClass.getSuperName());
150        println("Access flags:  0x" + Integer.toHexString(libraryClass.u2accessFlags));
151        println("  = " +
152                ((libraryClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0 ? "@ " : "") +
153                ClassUtil.externalClassAccessFlags(libraryClass.u2accessFlags) +
154                ((libraryClass.u2accessFlags & ClassConstants.INTERNAL_ACC_ENUM)      != 0 ? "enum " :
155                 (libraryClass.u2accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) == 0 ? "class " :
156                                                                                             "") +
157                ClassUtil.externalClassName(libraryClass.getName()) +
158                (libraryClass.getSuperName() == null ? "" : " extends "  +
159                ClassUtil.externalClassName(libraryClass.getSuperName())));
160        outdent();
161        println();
162
163        println("Interfaces (count = " + libraryClass.interfaceClasses.length + "):");
164        for (int index = 0; index < libraryClass.interfaceClasses.length; index++)
165        {
166            Clazz interfaceClass = libraryClass.interfaceClasses[index];
167            if (interfaceClass != null)
168            {
169                println("  + " + interfaceClass.getName());
170            }
171        }
172
173        println("Fields (count = " + libraryClass.fields.length + "):");
174        libraryClass.fieldsAccept(this);
175
176        println("Methods (count = " + libraryClass.methods.length + "):");
177        libraryClass.methodsAccept(this);
178    }
179
180
181    // Implementations for ConstantVisitor.
182
183    public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
184    {
185        println(visitorInfo(integerConstant) + " Integer [" +
186                integerConstant.getValue() + "]");
187    }
188
189
190    public void visitLongConstant(Clazz clazz, LongConstant longConstant)
191    {
192        println(visitorInfo(longConstant) + " Long [" +
193                longConstant.getValue() + "]");
194    }
195
196
197    public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
198    {
199        println(visitorInfo(floatConstant) + " Float [" +
200                floatConstant.getValue() + "]");
201    }
202
203
204    public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
205    {
206        println(visitorInfo(doubleConstant) + " Double [" +
207                doubleConstant.getValue() + "]");
208    }
209
210
211    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
212    {
213        println(visitorInfo(stringConstant) + " String [" +
214                clazz.getString(stringConstant.u2stringIndex) + "]");
215    }
216
217
218    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
219    {
220        println(visitorInfo(utf8Constant) + " Utf8 [" +
221                utf8Constant.getString() + "]");
222    }
223
224
225    public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
226    {
227        println(visitorInfo(fieldrefConstant) + " Fieldref [" +
228                clazz.getClassName(fieldrefConstant.u2classIndex)  + "." +
229                clazz.getName(fieldrefConstant.u2nameAndTypeIndex) + " " +
230                clazz.getType(fieldrefConstant.u2nameAndTypeIndex) + "]");
231    }
232
233
234    public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
235    {
236        println(visitorInfo(interfaceMethodrefConstant) + " InterfaceMethodref [" +
237                clazz.getClassName(interfaceMethodrefConstant.u2classIndex)  + "." +
238                clazz.getName(interfaceMethodrefConstant.u2nameAndTypeIndex) + " " +
239                clazz.getType(interfaceMethodrefConstant.u2nameAndTypeIndex) + "]");
240    }
241
242
243    public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
244    {
245        println(visitorInfo(methodrefConstant) + " Methodref [" +
246                clazz.getClassName(methodrefConstant.u2classIndex)  + "." +
247                clazz.getName(methodrefConstant.u2nameAndTypeIndex) + " " +
248                clazz.getType(methodrefConstant.u2nameAndTypeIndex) + "]");
249    }
250
251
252    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
253    {
254        println(visitorInfo(classConstant) + " Class [" +
255                clazz.getString(classConstant.u2nameIndex) + "]");
256    }
257
258
259    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
260    {
261        println(visitorInfo(nameAndTypeConstant) + " NameAndType [" +
262                clazz.getString(nameAndTypeConstant.u2nameIndex) + " " +
263                clazz.getString(nameAndTypeConstant.u2descriptorIndex) + "]");
264    }
265
266
267    // Implementations for MemberVisitor.
268
269    public void visitProgramField(ProgramClass programClass, ProgramField programField)
270    {
271        println(visitorInfo(programField) + " " +
272                "Field:        " +
273                programField.getName(programClass) + " " +
274                programField.getDescriptor(programClass));
275
276        indent();
277        println("Access flags: 0x" + Integer.toHexString(programField.u2accessFlags));
278        println("  = " +
279                ClassUtil.externalFullFieldDescription(programField.u2accessFlags,
280                                                       programField.getName(programClass),
281                                                       programField.getDescriptor(programClass)));
282
283        visitMember(programClass, programField);
284        outdent();
285    }
286
287
288    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
289    {
290        println(visitorInfo(programMethod) + " " +
291                "Method:       " +
292                programMethod.getName(programClass) +
293                programMethod.getDescriptor(programClass));
294
295        indent();
296        println("Access flags: 0x" + Integer.toHexString(programMethod.u2accessFlags));
297        println("  = " +
298                ClassUtil.externalFullMethodDescription(programClass.getName(),
299                                                        programMethod.u2accessFlags,
300                                                        programMethod.getName(programClass),
301                                                        programMethod.getDescriptor(programClass)));
302
303        visitMember(programClass, programMethod);
304        outdent();
305    }
306
307
308    private void visitMember(ProgramClass programClass, ProgramMember programMember)
309    {
310        if (programMember.u2attributesCount > 0)
311        {
312            println("Class member attributes (count = " + programMember.u2attributesCount + "):");
313            programMember.attributesAccept(programClass, this);
314        }
315    }
316
317
318    public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
319    {
320        println(visitorInfo(libraryField) + " " +
321                "Field:        " +
322                libraryField.getName(libraryClass) + " " +
323                libraryField.getDescriptor(libraryClass));
324
325        indent();
326        println("Access flags: 0x" + Integer.toHexString(libraryField.u2accessFlags));
327        println("  = " +
328                ClassUtil.externalFullFieldDescription(libraryField.u2accessFlags,
329                                                       libraryField.getName(libraryClass),
330                                                       libraryField.getDescriptor(libraryClass)));
331        outdent();
332    }
333
334
335    public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
336    {
337        println(visitorInfo(libraryMethod) + " " +
338                "Method:       " +
339                libraryMethod.getName(libraryClass) + " " +
340                libraryMethod.getDescriptor(libraryClass));
341
342        indent();
343        println("Access flags: 0x" + Integer.toHexString(libraryMethod.u2accessFlags));
344        println("  = " +
345                ClassUtil.externalFullMethodDescription(libraryClass.getName(),
346                                                        libraryMethod.u2accessFlags,
347                                                        libraryMethod.getName(libraryClass),
348                                                        libraryMethod.getDescriptor(libraryClass)));
349        outdent();
350    }
351
352
353    // Implementations for AttributeVisitor.
354    // Note that attributes are typically only referenced once, so we don't
355    // test if they are marked already.
356
357    public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
358    {
359        println(visitorInfo(unknownAttribute) +
360                " Unknown attribute (" + clazz.getString(unknownAttribute.u2attributeNameIndex) + ")");
361    }
362
363
364    public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
365    {
366        println(visitorInfo(sourceFileAttribute) +
367                " Source file attribute:");
368
369        indent();
370        clazz.constantPoolEntryAccept(sourceFileAttribute.u2sourceFileIndex, this);
371        outdent();
372    }
373
374
375    public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
376    {
377        println(visitorInfo(sourceDirAttribute) +
378                " Source dir attribute:");
379
380        indent();
381        clazz.constantPoolEntryAccept(sourceDirAttribute.u2sourceDirIndex, this);
382        outdent();
383    }
384
385
386    public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
387    {
388        println(visitorInfo(innerClassesAttribute) +
389                " Inner classes attribute (count = " + innerClassesAttribute.u2classesCount + ")");
390
391        indent();
392        innerClassesAttribute.innerClassEntriesAccept(clazz, this);
393        outdent();
394    }
395
396
397    public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
398    {
399        println(visitorInfo(enclosingMethodAttribute) +
400                " Enclosing method attribute:");
401
402        indent();
403        clazz.constantPoolEntryAccept(enclosingMethodAttribute.u2classIndex, this);
404
405        if (enclosingMethodAttribute.u2nameAndTypeIndex != 0)
406        {
407            clazz.constantPoolEntryAccept(enclosingMethodAttribute.u2nameAndTypeIndex, this);
408        }
409        outdent();
410    }
411
412
413    public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
414    {
415        println(visitorInfo(deprecatedAttribute) +
416                " Deprecated attribute");
417    }
418
419
420    public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
421    {
422        println(visitorInfo(syntheticAttribute) +
423                " Synthetic attribute");
424    }
425
426
427    public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
428    {
429        println(visitorInfo(signatureAttribute) +
430                " Signature attribute:");
431
432        indent();
433        clazz.constantPoolEntryAccept(signatureAttribute.u2signatureIndex, this);
434        outdent();
435    }
436
437
438    public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
439    {
440        println(visitorInfo(constantValueAttribute) +
441                " Constant value attribute:");
442
443        clazz.constantPoolEntryAccept(constantValueAttribute.u2constantValueIndex, this);
444    }
445
446
447    public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
448    {
449        println(visitorInfo(exceptionsAttribute) +
450                " Exceptions attribute (count = " + exceptionsAttribute.u2exceptionIndexTableLength + ")");
451
452        indent();
453        exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this);
454        outdent();
455    }
456
457
458    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
459    {
460        println(visitorInfo(codeAttribute) +
461                " Code attribute instructions (code length = "+ codeAttribute.u4codeLength +
462                ", locals = "+ codeAttribute.u2maxLocals +
463                ", stack = "+ codeAttribute.u2maxStack + "):");
464
465        indent();
466
467        codeAttribute.instructionsAccept(clazz, method, this);
468
469        println("Code attribute exceptions (count = " +
470                codeAttribute.u2exceptionTableLength + "):");
471
472        codeAttribute.exceptionsAccept(clazz, method, this);
473
474        println("Code attribute attributes (attribute count = " +
475                codeAttribute.u2attributesCount + "):");
476
477        codeAttribute.attributesAccept(clazz, method, this);
478
479        outdent();
480    }
481
482
483    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
484    {
485        println(visitorInfo(codeAttribute) +
486                " Stack map attribute (count = "+
487                stackMapAttribute.u2stackMapFramesCount + "):");
488
489        indent();
490        stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
491        outdent();
492    }
493
494
495    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
496    {
497        println(visitorInfo(codeAttribute) +
498                " Stack map table attribute (count = "+
499                stackMapTableAttribute.u2stackMapFramesCount + "):");
500
501        indent();
502        stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
503        outdent();
504    }
505
506
507    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
508    {
509        println(visitorInfo(lineNumberTableAttribute) +
510                " Line number table attribute (count = " +
511                lineNumberTableAttribute.u2lineNumberTableLength + ")");
512
513        indent();
514        lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
515        outdent();
516    }
517
518
519    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
520    {
521        println(visitorInfo(localVariableTableAttribute) +
522                " Local variable table attribute (count = " +
523                localVariableTableAttribute.u2localVariableTableLength + ")");
524
525        indent();
526        localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
527        outdent();
528    }
529
530
531    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
532    {
533        println(visitorInfo(localVariableTypeTableAttribute) +
534                " Local variable type table attribute (count = "+
535                localVariableTypeTableAttribute.u2localVariableTypeTableLength + ")");
536
537        indent();
538        localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
539        outdent();
540    }
541
542
543    public void visitRuntimeVisibleAnnotationsAttribute(Clazz clazz, RuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute)
544    {
545        println(visitorInfo(runtimeVisibleAnnotationsAttribute) +
546                " Runtime visible annotations attribute:");
547
548        indent();
549        runtimeVisibleAnnotationsAttribute.annotationsAccept(clazz, this);
550        outdent();
551    }
552
553
554    public void visitRuntimeInvisibleAnnotationsAttribute(Clazz clazz, RuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute)
555    {
556        println(visitorInfo(runtimeInvisibleAnnotationsAttribute) +
557                " Runtime invisible annotations attribute:");
558
559        indent();
560        runtimeInvisibleAnnotationsAttribute.annotationsAccept(clazz, this);
561        outdent();
562    }
563
564
565    public void visitRuntimeVisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeVisibleParameterAnnotationsAttribute runtimeVisibleParameterAnnotationsAttribute)
566    {
567        println(visitorInfo(runtimeVisibleParameterAnnotationsAttribute) +
568                " Runtime visible parameter annotations attribute (parameter count = " + runtimeVisibleParameterAnnotationsAttribute.u2parametersCount + "):");
569
570        indent();
571        runtimeVisibleParameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
572        outdent();
573    }
574
575
576    public void visitRuntimeInvisibleParameterAnnotationsAttribute(Clazz clazz, Method method, RuntimeInvisibleParameterAnnotationsAttribute runtimeInvisibleParameterAnnotationsAttribute)
577    {
578        println(visitorInfo(runtimeInvisibleParameterAnnotationsAttribute) +
579                " Runtime invisible parameter annotations attribute (parameter count = " + runtimeInvisibleParameterAnnotationsAttribute.u2parametersCount + "):");
580
581        indent();
582        runtimeInvisibleParameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
583        outdent();
584    }
585
586
587    public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
588    {
589        println(visitorInfo(annotationDefaultAttribute) +
590                " Annotation default attribute:");
591
592        indent();
593        annotationDefaultAttribute.defaultValueAccept(clazz, this);
594        outdent();
595    }
596
597
598    // Implementations for InnerClassesInfoVisitor.
599
600    public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
601    {
602        println(visitorInfo(innerClassesInfo) +
603                " InnerClassesInfo:");
604
605        indent();
606        innerClassesInfo.innerClassConstantAccept(clazz, this);
607        innerClassesInfo.outerClassConstantAccept(clazz, this);
608        innerClassesInfo.innerNameConstantAccept(clazz, this);
609        outdent();
610    }
611
612
613    // Implementations for InstructionVisitor.
614
615    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
616    {
617        println(instruction.toString(offset));
618    }
619
620
621    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
622    {
623        println(constantInstruction.toString(offset));
624
625        indent();
626        clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
627        outdent();
628    }
629
630
631    public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
632    {
633        println(tableSwitchInstruction.toString(offset));
634
635        indent();
636
637        int[] jumpOffsets = tableSwitchInstruction.jumpOffsets;
638
639        for (int index = 0; index < jumpOffsets.length; index++)
640        {
641            int jumpOffset = jumpOffsets[index];
642            println(Integer.toString(tableSwitchInstruction.lowCase + index)  + ": offset = " + jumpOffset + ", target = " + (offset + jumpOffset));
643        }
644
645        int defaultOffset = tableSwitchInstruction.defaultOffset;
646        println("default: offset = " + defaultOffset + ", target = "+ (offset + defaultOffset));
647
648        outdent();
649    }
650
651
652    public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
653    {
654        println(lookUpSwitchInstruction.toString(offset));
655
656        indent();
657
658        int[] cases       = lookUpSwitchInstruction.cases;
659        int[] jumpOffsets = lookUpSwitchInstruction.jumpOffsets;
660
661        for (int index = 0; index < jumpOffsets.length; index++)
662        {
663            int jumpOffset = jumpOffsets[index];
664            println(Integer.toString(cases[index])  + ": offset = " + jumpOffset + ", target = " + (offset + jumpOffset));
665        }
666
667        int defaultOffset = lookUpSwitchInstruction.defaultOffset;
668        println("default: offset = " + defaultOffset + ", target = "+ (offset + defaultOffset));
669
670        outdent();
671    }
672
673
674    // Implementations for ExceptionInfoVisitor.
675
676    public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
677    {
678        println(visitorInfo(exceptionInfo) +
679                " ExceptionInfo (" +
680                exceptionInfo.u2startPC + " -> " +
681                exceptionInfo.u2endPC + ": " +
682                exceptionInfo.u2handlerPC + "):");
683
684        if (exceptionInfo.u2catchType != 0)
685        {
686            clazz.constantPoolEntryAccept(exceptionInfo.u2catchType, this);
687        }
688    }
689
690
691    // Implementations for StackMapFrameVisitor.
692
693    public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame)
694    {
695        println(visitorInfo(sameZeroFrame) +
696                " [" + offset  + "]" +
697                " Var: ..., Stack: (empty)");
698    }
699
700
701    public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
702    {
703        print(visitorInfo(sameOneFrame) +
704              " [" + offset  + "]" +
705              " Var: ..., Stack: ");
706
707        sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
708
709        println();
710    }
711
712
713    public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame)
714    {
715        println(visitorInfo(lessZeroFrame) +
716                " [" + offset  + "]" +
717                " Var: -" + lessZeroFrame.choppedVariablesCount +
718                ", Stack: (empty)");
719    }
720
721
722    public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
723    {
724        print(visitorInfo(moreZeroFrame) +
725              " [" + offset  + "]" +
726              " Var: ...");
727
728        moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
729
730        ps.println(", Stack: (empty)");
731    }
732
733
734    public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
735    {
736        print(visitorInfo(fullFrame) +
737              " [" + offset  + "]" +
738              " Var: ");
739
740        fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
741
742        ps.print(", Stack: ");
743
744        fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
745
746        println();
747    }
748
749
750    // Implementations for VerificationTypeVisitor.
751
752    public void visitIntegerType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, IntegerType integerType)
753    {
754        ps.print("[i]");
755    }
756
757
758    public void visitFloatType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FloatType floatType)
759    {
760        ps.print("[f]");
761    }
762
763
764    public void visitLongType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LongType longType)
765    {
766        ps.print("[l]");
767    }
768
769
770    public void visitDoubleType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, DoubleType doubleType)
771    {
772        ps.print("[d]");
773    }
774
775
776    public void visitTopType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TopType topType)
777    {
778        ps.print("[T]");
779    }
780
781
782    public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType)
783    {
784        ps.print("[a:" + clazz.getClassName(objectType.u2classIndex) + "]");
785    }
786
787
788    public void visitNullType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, NullType nullType)
789    {
790        ps.print("[n]");
791    }
792
793
794    public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
795    {
796        ps.print("[u:" + uninitializedType.u2newInstructionOffset + "]");
797    }
798
799
800    public void visitUninitializedThisType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedThisType uninitializedThisType)
801    {
802        ps.print("[u:this]");
803    }
804
805
806    // Implementations for LineNumberInfoVisitor.
807
808    public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
809    {
810        println("[" + lineNumberInfo.u2startPC + "] -> line " +
811                lineNumberInfo.u2lineNumber);
812    }
813
814
815    // Implementations for LocalVariableInfoVisitor.
816
817    public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
818    {
819        println("#" + localVariableInfo.u2index + ": " +
820                localVariableInfo.u2startPC + " -> " +
821                (localVariableInfo.u2startPC + localVariableInfo.u2length) + " [" +
822                clazz.getString(localVariableInfo.u2descriptorIndex) + " " +
823                clazz.getString(localVariableInfo.u2nameIndex) + "]");
824    }
825
826
827    // Implementations for LocalVariableTypeInfoVisitor.
828
829    public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
830    {
831        println("#" + localVariableTypeInfo.u2index + ": " +
832                localVariableTypeInfo.u2startPC + " -> " +
833                (localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length) + " [" +
834                clazz.getString(localVariableTypeInfo.u2signatureIndex) + " " +
835                clazz.getString(localVariableTypeInfo.u2nameIndex) + "]");
836    }
837
838
839    // Implementations for AnnotationVisitor.
840
841    public void visitAnnotation(Clazz clazz, Annotation annotation)
842    {
843        println(visitorInfo(annotation) +
844                " Annotation [" + clazz.getString(annotation.u2typeIndex) + "]:");
845
846        indent();
847        annotation.elementValuesAccept(clazz, this);
848        outdent();
849    }
850
851
852    // Implementations for ElementValueVisitor.
853
854    public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
855    {
856        println(visitorInfo(constantElementValue) +
857                " Constant element value [" +
858                (constantElementValue.u2elementNameIndex == 0 ? "(default)" :
859                clazz.getString(constantElementValue.u2elementNameIndex)) + " '" +
860                constantElementValue.u1tag + "']");
861
862        indent();
863        clazz.constantPoolEntryAccept(constantElementValue.u2constantValueIndex, this);
864        outdent();
865    }
866
867
868    public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
869    {
870        println(visitorInfo(enumConstantElementValue) +
871                " Enum constant element value [" +
872                (enumConstantElementValue.u2elementNameIndex == 0 ? "(default)" :
873                clazz.getString(enumConstantElementValue.u2elementNameIndex)) + ", " +
874                clazz.getString(enumConstantElementValue.u2typeNameIndex)  + ", " +
875                clazz.getString(enumConstantElementValue.u2constantNameIndex) + "]");
876    }
877
878
879    public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
880    {
881        println(visitorInfo(classElementValue) +
882                " Class element value [" +
883                (classElementValue.u2elementNameIndex == 0 ? "(default)" :
884                clazz.getString(classElementValue.u2elementNameIndex)) + ", " +
885                clazz.getString(classElementValue.u2classInfoIndex) + "]");
886    }
887
888
889    public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
890    {
891        println(visitorInfo(annotationElementValue) +
892                " Annotation element value [" +
893                (annotationElementValue.u2elementNameIndex == 0 ? "(default)" :
894                clazz.getString(annotationElementValue.u2elementNameIndex)) + "]:");
895
896        indent();
897        annotationElementValue.annotationAccept(clazz, this);
898        outdent();
899    }
900
901
902    public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
903    {
904        println(visitorInfo(arrayElementValue) +
905                " Array element value [" +
906                (arrayElementValue.u2elementNameIndex == 0 ? "(default)" :
907                clazz.getString(arrayElementValue.u2elementNameIndex)) + "]:");
908
909        indent();
910        arrayElementValue.elementValuesAccept(clazz, annotation, this);
911        outdent();
912    }
913
914
915    // Small utility methods.
916
917    private void indent()
918    {
919        indentation++;
920    }
921
922    private void outdent()
923    {
924        indentation--;
925    }
926
927    private void println(String string)
928    {
929        print(string);
930        println();
931
932    }
933
934    private void print(String string)
935    {
936        for (int index = 0; index < indentation; index++)
937        {
938            ps.print(INDENTATION);
939        }
940
941        ps.print(string);
942    }
943
944    private void println()
945    {
946        ps.println();
947    }
948
949
950    private String visitorInfo(VisitorAccepter visitorAccepter)
951    {
952        return visitorAccepter.getVisitorInfo() == null ? "-" : "+";
953    }
954}
955