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.*; 26 import proguard.classfile.constant.*; 27 import proguard.classfile.constant.visitor.ConstantVisitor; 28 import proguard.classfile.util.SimplifiedVisitor; 29 import proguard.classfile.visitor.ClassVisitor; 30 31 /** 32 * This AttributeVisitor recursively marks all necessary inner class information 33 * in the attributes that it visits. 34 * 35 * @see UsageMarker 36 * 37 * @author Eric Lafortune 38 */ 39 public class InnerUsageMarker 40 extends SimplifiedVisitor 41 implements AttributeVisitor, 42 InnerClassesInfoVisitor, 43 ConstantVisitor, 44 ClassVisitor 45 { 46 private final UsageMarker usageMarker; 47 48 // Fields acting as a return parameters for several methods. 49 private boolean attributeUsed; 50 private boolean classUsed; 51 52 53 /** 54 * Creates a new InnerUsageMarker. 55 * @param usageMarker the usage marker that is used to mark the classes 56 * and class members. 57 */ InnerUsageMarker(UsageMarker usageMarker)58 public InnerUsageMarker(UsageMarker usageMarker) 59 { 60 this.usageMarker = usageMarker; 61 } 62 63 64 // Implementations for AttributeVisitor. 65 visitAnyAttribute(Clazz clazz, Attribute attribute)66 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 67 68 visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)69 public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) 70 { 71 // Mark the necessary inner classes information. 72 attributeUsed = false; 73 innerClassesAttribute.innerClassEntriesAccept(clazz, this); 74 75 if (attributeUsed) 76 { 77 // We got a positive used flag, so some inner class is being used. 78 // Mark this attribute as being used as well. 79 usageMarker.markAsUsed(innerClassesAttribute); 80 81 markConstant(clazz, innerClassesAttribute.u2attributeNameIndex); 82 } 83 } 84 85 86 // Implementations for InnerClassesInfoVisitor. 87 visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)88 public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) 89 { 90 boolean innerClassesInfoUsed = usageMarker.isUsed(innerClassesInfo); 91 92 if (!innerClassesInfoUsed) 93 { 94 // Check if the inner class (if any) is marked as being used. 95 classUsed = true; 96 innerClassesInfo.innerClassConstantAccept(clazz, this); 97 innerClassesInfoUsed = classUsed; 98 99 // Check if the outer class (if any) is marked as being used. 100 classUsed = true; 101 innerClassesInfo.outerClassConstantAccept(clazz, this); 102 innerClassesInfoUsed &= classUsed; 103 104 // If both the inner class and the outer class are marked as being 105 // used, then mark this InnerClassesInfo as well. 106 if (innerClassesInfoUsed) 107 { 108 usageMarker.markAsUsed(innerClassesInfo); 109 110 innerClassesInfo.innerNameConstantAccept(clazz, this); 111 } 112 } 113 114 // The return value. 115 attributeUsed |= innerClassesInfoUsed; 116 } 117 118 119 // Implementations for ConstantVisitor. 120 visitClassConstant(Clazz clazz, ClassConstant classConstant)121 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 122 { 123 classUsed = usageMarker.isUsed(classConstant); 124 125 // Is the class constant marked as being used? 126 if (!classUsed) 127 { 128 // Check the referenced class. 129 classUsed = true; 130 classConstant.referencedClassAccept(this); 131 132 // Is the referenced class marked as being used? 133 if (classUsed) 134 { 135 // Mark the class constant and its Utf8 constant. 136 usageMarker.markAsUsed(classConstant); 137 138 markConstant(clazz, classConstant.u2nameIndex); 139 } 140 } 141 } 142 143 visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)144 public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) 145 { 146 usageMarker.markAsUsed(utf8Constant); 147 } 148 149 150 // Implementations for ClassVisitor. 151 visitProgramClass(ProgramClass programClass)152 public void visitProgramClass(ProgramClass programClass) 153 { 154 classUsed = usageMarker.isUsed(programClass); 155 } 156 157 visitLibraryClass(LibraryClass libraryClass)158 public void visitLibraryClass(LibraryClass libraryClass) 159 { 160 classUsed = true; 161 } 162 163 164 // Small utility methods. 165 166 /** 167 * Marks the given constant pool entry of the given class. This includes 168 * visiting any other referenced constant pool entries. 169 */ markConstant(Clazz clazz, int index)170 private void markConstant(Clazz clazz, int index) 171 { 172 clazz.constantPoolEntryAccept(index, this); 173 } 174 } 175