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