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