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 */ 21 package proguard.shrink; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.AttributeVisitor; 26 import proguard.classfile.util.*; 27 import proguard.classfile.visitor.*; 28 29 import 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 */ 40 public class UsagePrinter 41 extends SimplifiedVisitor 42 implements 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 */ UsagePrinter(UsageMarker usageMarker, boolean printUnusedItems)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 */ UsagePrinter(UsageMarker usageMarker, boolean printUnusedItems, PrintStream printStream)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 visitProgramClass(ProgramClass programClass)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 visitProgramField(ProgramClass programClass, ProgramField programField)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 visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)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 visitAnyAttribute(Clazz clazz, Attribute attribute)154 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 155 156 visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)157 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 158 { 159 codeAttribute.attributesAccept(clazz, method, this); 160 } 161 162 visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)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 */ printClassNameHeader()176 private void printClassNameHeader() 177 { 178 if (className != null) 179 { 180 ps.println(ClassUtil.externalClassName(className) + ":"); 181 className = null; 182 } 183 } 184 } 185