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