1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2014 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.shrink;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.visitor.AttributeVisitor;
26import proguard.classfile.util.*;
27import proguard.classfile.visitor.*;
28
29import java.io.PrintStream;
30
31
32/**
33 * This ClassVisitor prints out the classes and class members that have been
34 * marked as being used (or not used).
35 *
36 * @see UsageMarker
37 *
38 * @author Eric Lafortune
39 */
40public class UsagePrinter
41extends      SimplifiedVisitor
42implements   ClassVisitor,
43             MemberVisitor,
44             AttributeVisitor
45{
46    private final UsageMarker usageMarker;
47    private final boolean     printUnusedItems;
48    private final PrintStream ps;
49
50    // A field to remember the class name, if a header is needed for class members.
51    private String      className;
52
53
54    /**
55     * Creates a new UsagePrinter that prints to <code>System.out</code>.
56     * @param usageMarker      the usage marker that was used to mark the
57     *                         classes and class members.
58     * @param printUnusedItems a flag that indicates whether only unused items
59     *                         should be printed, or alternatively, only used
60     *                         items.
61     */
62    public UsagePrinter(UsageMarker usageMarker,
63                        boolean     printUnusedItems)
64    {
65        this(usageMarker, printUnusedItems, System.out);
66    }
67
68
69    /**
70     * Creates a new UsagePrinter that prints to the given stream.
71     * @param usageMarker      the usage marker that was used to mark the
72     *                         classes and class members.
73     * @param printUnusedItems a flag that indicates whether only unused items
74     *                         should be printed, or alternatively, only used
75     *                         items.
76     * @param printStream      the stream to which to print.
77     */
78    public UsagePrinter(UsageMarker usageMarker,
79                        boolean     printUnusedItems,
80                        PrintStream printStream)
81    {
82        this.usageMarker      = usageMarker;
83        this.printUnusedItems = printUnusedItems;
84        this.ps               = printStream;
85    }
86
87
88    // Implementations for ClassVisitor.
89
90    public void visitProgramClass(ProgramClass programClass)
91    {
92        if (usageMarker.isUsed(programClass))
93        {
94            if (printUnusedItems)
95            {
96                className = programClass.getName();
97
98                programClass.fieldsAccept(this);
99                programClass.methodsAccept(this);
100
101                className = null;
102            }
103            else
104            {
105                ps.println(ClassUtil.externalClassName(programClass.getName()));
106            }
107        }
108        else
109        {
110            if (printUnusedItems)
111            {
112                ps.println(ClassUtil.externalClassName(programClass.getName()));
113            }
114        }
115    }
116
117
118    // Implementations for MemberVisitor.
119
120    public void visitProgramField(ProgramClass programClass, ProgramField programField)
121    {
122        if (usageMarker.isUsed(programField) ^ printUnusedItems)
123        {
124            printClassNameHeader();
125
126            ps.println("    " +
127                       ClassUtil.externalFullFieldDescription(
128                           programField.getAccessFlags(),
129                           programField.getName(programClass),
130                           programField.getDescriptor(programClass)));
131        }
132    }
133
134
135    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
136    {
137        if (usageMarker.isUsed(programMethod) ^ printUnusedItems)
138        {
139            printClassNameHeader();
140
141            ps.print("    ");
142            programMethod.attributesAccept(programClass, this);
143            ps.println(ClassUtil.externalFullMethodDescription(
144                           programClass.getName(),
145                           programMethod.getAccessFlags(),
146                           programMethod.getName(programClass),
147                           programMethod.getDescriptor(programClass)));
148        }
149    }
150
151
152    // Implementations for AttributeVisitor.
153
154    public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
155
156
157    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
158    {
159        codeAttribute.attributesAccept(clazz, method, this);
160    }
161
162
163    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
164    {
165        ps.print(lineNumberTableAttribute.getLowestLineNumber() + ":" +
166                 lineNumberTableAttribute.getHighestLineNumber() + ":");
167    }
168
169
170    // Small utility methods.
171
172    /**
173     * Prints the class name field. The field is then cleared, so it is not
174     * printed again.
175     */
176    private void printClassNameHeader()
177    {
178        if (className != null)
179        {
180            ps.println(ClassUtil.externalClassName(className) + ":");
181            className = null;
182        }
183    }
184}
185