• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package proguard.shrink;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.util.ClassUtil;
25 import proguard.classfile.visitor.*;
26 
27 import java.io.PrintStream;
28 
29 
30 /**
31  * This ClassVisitor     and MemberVisitor prints out the reasons why
32  * classes and class members have been marked as being used.
33  *
34  * @see UsageMarker
35  *
36  * @author Eric Lafortune
37  */
38 public class ShortestUsagePrinter
39 implements   ClassVisitor,
40              MemberVisitor
41 {
42     private final ShortestUsageMarker shortestUsageMarker;
43     private final boolean             verbose;
44     private final PrintStream         ps;
45 
46 
47     /**
48      * Creates a new UsagePrinter that prints verbosely to <code>System.out</code>.
49      * @param shortestUsageMarker the usage marker that was used to mark the
50      *                            classes and class members.
51      */
ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker)52     public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker)
53     {
54         this(shortestUsageMarker, true);
55     }
56 
57 
58     /**
59      * Creates a new UsagePrinter that prints to the given stream.
60      * @param shortestUsageMarker the usage marker that was used to mark the
61      *                            classes and class members.
62      * @param verbose             specifies whether the output should be verbose.
63      */
ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker, boolean verbose)64     public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker,
65                                 boolean             verbose)
66     {
67         this(shortestUsageMarker, verbose, System.out);
68     }
69 
70     /**
71      * Creates a new UsagePrinter that prints to the given stream.
72      * @param shortestUsageMarker the usage marker that was used to mark the
73      *                            classes and class members.
74      * @param verbose             specifies whether the output should be verbose.
75      * @param printStream         the stream to which to print.
76      */
ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker, boolean verbose, PrintStream printStream)77     public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker,
78                                 boolean             verbose,
79                                 PrintStream         printStream)
80     {
81         this.shortestUsageMarker = shortestUsageMarker;
82         this.verbose             = verbose;
83         this.ps                  = printStream;
84     }
85 
86 
87     // Implementations for ClassVisitor.
88 
visitProgramClass(ProgramClass programClass)89     public void visitProgramClass(ProgramClass programClass)
90     {
91         // Print the name of this class.
92         ps.println(ClassUtil.externalClassName(programClass.getName()));
93 
94         // Print the reason for keeping this class.
95         printReason(programClass);
96     }
97 
98 
visitLibraryClass(LibraryClass libraryClass)99     public void visitLibraryClass(LibraryClass libraryClass)
100     {
101         // Print the name of this class.
102         ps.println(ClassUtil.externalClassName(libraryClass.getName()));
103 
104         // Print the reason for keeping this class.
105         ps.println("  is a library class.\n");
106     }
107 
108 
109     // Implementations for MemberVisitor.
110 
visitProgramField(ProgramClass programClass, ProgramField programField)111     public void visitProgramField(ProgramClass programClass, ProgramField programField)
112     {
113         // Print the name of this field.
114         String name = programField.getName(programClass);
115         String type = programField.getDescriptor(programClass);
116 
117         ps.println(ClassUtil.externalClassName(programClass.getName()) +
118                    (verbose ?
119                         ": " + ClassUtil.externalFullFieldDescription(0, name, type):
120                         "."  + name) +
121                    lineNumberRange(programClass, programField));
122 
123         // Print the reason for keeping this method.
124         printReason(programField);
125     }
126 
127 
visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)128     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
129     {
130         // Print the name of this method.
131         String name = programMethod.getName(programClass);
132         String type = programMethod.getDescriptor(programClass);
133 
134         ps.println(ClassUtil.externalClassName(programClass.getName()) +
135                    (verbose ?
136                         ": " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, name, type):
137                         "."  + name) +
138                    lineNumberRange(programClass, programMethod));
139 
140         // Print the reason for keeping this method.
141         printReason(programMethod);
142     }
143 
144 
visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)145     public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
146     {
147         // Print the name of this field.
148         String name = libraryField.getName(libraryClass);
149         String type = libraryField.getDescriptor(libraryClass);
150 
151         ps.println(ClassUtil.externalClassName(libraryClass.getName()) +
152                    (verbose ?
153                         ": " + ClassUtil.externalFullFieldDescription(0, name, type):
154                         "."  + name));
155 
156         // Print the reason for keeping this field.
157         ps.println("  is a library field.\n");
158     }
159 
160 
visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)161     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
162     {
163         // Print the name of this method.
164         String name = libraryMethod.getName(libraryClass);
165         String type = libraryMethod.getDescriptor(libraryClass);
166 
167         ps.println(ClassUtil.externalClassName(libraryClass.getName()) +
168                    (verbose ?
169                         ": " + ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, name, type):
170                         "."  + name));
171 
172         // Print the reason for keeping this method.
173         ps.println("  is a library method.\n");
174     }
175 
176 
177     // Small utility methods.
178 
printReason(VisitorAccepter visitorAccepter)179     private void printReason(VisitorAccepter visitorAccepter)
180     {
181         if (shortestUsageMarker.isUsed(visitorAccepter))
182         {
183             ShortestUsageMark shortestUsageMark = shortestUsageMarker.getShortestUsageMark(visitorAccepter);
184 
185             // Print the reason for keeping this class.
186             ps.print("  " + shortestUsageMark.getReason());
187 
188             // Print the class or method that is responsible, with its reasons.
189             shortestUsageMark.acceptClassVisitor(this);
190             shortestUsageMark.acceptMemberVisitor(this);
191         }
192         else
193         {
194             ps.println("  is not being kept.\n");
195         }
196     }
197 
198 
199     /**
200      * Returns the line number range of the given class member, followed by a
201      * colon, or just an empty String if no range is available.
202      */
lineNumberRange(ProgramClass programClass, ProgramMember programMember)203     private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember)
204     {
205         String range = programMember.getLineNumberRange(programClass);
206         return range != null ?
207             (" (" + range + ")") :
208             "";
209     }
210 }
211