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.optimize.peephole; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.*; 26 import proguard.classfile.constant.ClassConstant; 27 import proguard.classfile.constant.visitor.ConstantVisitor; 28 import proguard.classfile.util.SimplifiedVisitor; 29 import proguard.classfile.visitor.ClassVisitor; 30 31 import java.util.Arrays; 32 33 /** 34 * This ClassVisitor removes InnerClasses and EnclosingMethod attributes in 35 * classes that are retargeted or that refer to classes that are retargeted. 36 * 37 * @see ClassMerger 38 * @author Eric Lafortune 39 */ 40 public class RetargetedInnerClassAttributeRemover 41 extends SimplifiedVisitor 42 implements ClassVisitor, 43 AttributeVisitor, 44 InnerClassesInfoVisitor, 45 ConstantVisitor 46 { 47 private boolean retargeted; 48 49 50 // Implementations for ClassVisitor. 51 visitProgramClass(ProgramClass programClass)52 public void visitProgramClass(ProgramClass programClass) 53 { 54 int attributesCount = programClass.u2attributesCount; 55 Attribute[] attributes = programClass.attributes; 56 57 int newAtributesCount = 0; 58 59 // Copy over all non-retargeted attributes. 60 for (int index = 0; index < attributesCount; index++) 61 { 62 Attribute attribute = attributes[index]; 63 64 // Check if it's an InnerClasses or EnclosingMethod attribute in 65 // a retargeted class or referring to a retargeted class. 66 retargeted = false; 67 attribute.accept(programClass, this); 68 if (!retargeted) 69 { 70 attributes[newAtributesCount++] = attribute; 71 } 72 } 73 74 // Clean up any remaining array elements. 75 Arrays.fill(attributes, newAtributesCount, attributesCount, null); 76 77 // Update the number of attributes. 78 programClass.u2attributesCount = newAtributesCount; 79 } 80 81 82 // Implementations for AttributeVisitor. 83 visitAnyAttribute(Clazz clazz, Attribute attribute)84 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 85 86 visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)87 public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) 88 { 89 // Check whether the class itself is retargeted. 90 checkTarget(clazz); 91 92 if (!retargeted) 93 { 94 // Check whether the referenced classes are retargeted. 95 innerClassesAttribute.innerClassEntriesAccept(clazz, this); 96 int classesCount = innerClassesAttribute.u2classesCount; 97 InnerClassesInfo[] classes = innerClassesAttribute.classes; 98 99 int newClassesCount = 0; 100 101 // Copy over all non-retargeted attributes. 102 for (int index = 0; index < classesCount; index++) 103 { 104 InnerClassesInfo classInfo = classes[index]; 105 106 // Check if the outer class or inner class is a retargeted class. 107 retargeted = false; 108 classInfo.outerClassConstantAccept(clazz, this); 109 classInfo.innerClassConstantAccept(clazz, this); 110 if (!retargeted) 111 { 112 classes[newClassesCount++] = classInfo; 113 } 114 } 115 116 // Clean up any remaining array elements. 117 Arrays.fill(classes, newClassesCount, classesCount, null); 118 119 // Update the number of classes. 120 innerClassesAttribute.u2classesCount = newClassesCount; 121 122 // Remove the attribute altogether if it's empty. 123 retargeted = newClassesCount == 0; 124 } 125 } 126 127 visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)128 public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) 129 { 130 // Check whether the class itself is retargeted. 131 checkTarget(clazz); 132 133 // Check whether the referenced class is retargeted. 134 checkTarget(enclosingMethodAttribute.referencedClass); 135 } 136 137 138 // Implementations for InnerClassesInfoVisitor. 139 visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)140 public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) 141 { 142 // Check whether the inner class or the outer class are retargeted. 143 innerClassesInfo.innerClassConstantAccept(clazz, this); 144 innerClassesInfo.outerClassConstantAccept(clazz, this); 145 } 146 147 148 // Implementations for ConstantVisitor. 149 visitClassConstant(Clazz clazz, ClassConstant classConstant)150 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 151 { 152 // Check whether the referenced class is retargeted. 153 checkTarget(classConstant.referencedClass); 154 } 155 156 157 // Small utility methods. 158 159 /** 160 * Sets the global return value to true if the given class is retargeted. 161 */ checkTarget(Clazz clazz)162 private void checkTarget(Clazz clazz) 163 { 164 if (clazz != null && 165 ClassMerger.getTargetClass(clazz) != null) 166 { 167 retargeted = true; 168 } 169 } 170 }