AccessFixer.java revision cfead78069f3dc32998dc118ee08cab3867acea2
1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2011 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.classfile.editor; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.*; 25import proguard.classfile.attribute.visitor.*; 26import proguard.classfile.constant.*; 27import proguard.classfile.constant.visitor.ConstantVisitor; 28import proguard.classfile.util.*; 29import proguard.classfile.visitor.*; 30 31/** 32 * This ConstantVisitor fixes the access modifiers of all classes and class 33 * members that are referenced by the constants that it visits. 34 * 35 * @author Eric Lafortune 36 */ 37public class AccessFixer 38extends SimplifiedVisitor 39implements ConstantVisitor, 40 ClassVisitor, 41 MemberVisitor 42{ 43 private MyReferencedClassFinder referencedClassFinder = new MyReferencedClassFinder(); 44 45 private Clazz referencingClass; 46 private Clazz referencedClass; 47 48 49 // Implementations for ConstantVisitor. 50 51 public void visitAnyConstant(Clazz clazz, Constant constant) {} 52 53 54 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 55 { 56 referencingClass = clazz; 57 referencedClass = stringConstant.referencedClass; 58 59 // Make sure the access flags of the referenced class or class member, 60 // if any, are acceptable. 61 stringConstant.referencedClassAccept(this); 62 stringConstant.referencedMemberAccept(this); 63 } 64 65 66 public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) 67 { 68 // Check the bootstrap method. 69 invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this); 70 } 71 72 73 public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) 74 { 75 // Check the method reference. 76 clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); 77 } 78 79 80 public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) 81 { 82 referencingClass = clazz; 83 84 // Remember the specified class, since it might be different from 85 // the referenced class that actually contains the class member. 86 clazz.constantPoolEntryAccept(refConstant.u2classIndex, referencedClassFinder); 87 88 // Make sure the access flags of the referenced class member are 89 // acceptable. 90 refConstant.referencedMemberAccept(this); 91 } 92 93 94 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 95 { 96 referencingClass = clazz; 97 98 // Make sure the access flags of the referenced class are acceptable. 99 classConstant.referencedClassAccept(this); 100 } 101 102 103 // Implementations for ClassVisitor. 104 105 public void visitLibraryClass(LibraryClass libraryClass) {} 106 107 108 public void visitProgramClass(ProgramClass programClass) 109 { 110 int currentAccessFlags = programClass.getAccessFlags(); 111 int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); 112 113 // Compute the required access level. 114 Clazz referencingClass = this.referencingClass; 115 int requiredAccessLevel = 116 inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : 117 AccessUtil.PUBLIC; 118 119 // Fix the class access flags if necessary. 120 if (currentAccessLevel < requiredAccessLevel) 121 { 122 programClass.u2accessFlags = 123 AccessUtil.replaceAccessFlags(currentAccessFlags, 124 AccessUtil.accessFlags(requiredAccessLevel)); 125 } 126 } 127 128 129 // Implementations for MemberVisitor. 130 131 public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {} 132 133 134 public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) 135 { 136 int currentAccessFlags = programMember.getAccessFlags(); 137 int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); 138 139 // Compute the required access level. 140 int requiredAccessLevel = 141 programClass.equals(referencingClass) ? AccessUtil.PRIVATE : 142 inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : 143 referencedClass.extends_(referencingClass) && 144 referencingClass.extends_(programClass) ? AccessUtil.PROTECTED : 145 AccessUtil.PUBLIC; 146 147 // Fix the class member access flags if necessary. 148 if (currentAccessLevel < requiredAccessLevel) 149 { 150 programMember.u2accessFlags = 151 AccessUtil.replaceAccessFlags(currentAccessFlags, 152 AccessUtil.accessFlags(requiredAccessLevel)); 153 } 154 } 155 156 157 /** 158 * This ConstantVisitor returns the referenced class of the class constant 159 * that it visits. 160 */ 161 private class MyReferencedClassFinder 162 extends SimplifiedVisitor 163 implements ConstantVisitor 164 { 165 // Implementations for ConstantVisitor. 166 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 167 { 168 referencedClass = classConstant.referencedClass; 169 } 170 } 171 172 173 // Small utility methods. 174 175 private boolean inSamePackage(ProgramClass class1, Clazz class2) 176 { 177 return ClassUtil.internalPackageName(class1.getName()).equals( 178 ClassUtil.internalPackageName(class2.getName())); 179 } 180} 181