diff options
Diffstat (limited to 'src/proguard/classfile/editor/AccessFixer.java')
-rw-r--r-- | src/proguard/classfile/editor/AccessFixer.java | 234 |
1 files changed, 135 insertions, 99 deletions
diff --git a/src/proguard/classfile/editor/AccessFixer.java b/src/proguard/classfile/editor/AccessFixer.java index d770531..3c41159 100644 --- a/src/proguard/classfile/editor/AccessFixer.java +++ b/src/proguard/classfile/editor/AccessFixer.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -21,160 +21,196 @@ package proguard.classfile.editor; import proguard.classfile.*; -import proguard.classfile.attribute.*; -import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; -import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; /** - * This ConstantVisitor fixes the access modifiers of all classes and class - * members that are referenced by the constants that it visits. + * This ClassVisitor fixes the access modifiers of all classes and class + * members that are referenced by the classes that it visits. * * @author Eric Lafortune */ public class AccessFixer -extends SimplifiedVisitor -implements ConstantVisitor, - ClassVisitor, - MemberVisitor +extends ReferencedClassVisitor +implements ClassVisitor { - private MyReferencedClassFinder referencedClassFinder = new MyReferencedClassFinder(); + /** + * Creates a new AccessFixer. + */ + public AccessFixer() + { + // Unfortunately, the inner class must be static to be passed to the + // super constructor. We therefore can't let it refer to this class; + // we'll let this class refer to the inner class instead. + super(new MyAccessFixer()); + } - private Clazz referencingClass; - private Clazz referencedClass; + // Overridden methods for ClassVisitor. - // Implementations for ConstantVisitor. + public void visitProgramClass(ProgramClass programClass) + { + // Remember the referencing class. + ((MyAccessFixer)classVisitor).referencingClass = programClass; - public void visitAnyConstant(Clazz clazz, Constant constant) {} + // Start visiting and fixing the referenced classes and class members. + super.visitProgramClass(programClass); + } - public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + public void visitLibraryClass(LibraryClass libraryClass) { - referencingClass = clazz; - referencedClass = stringConstant.referencedClass; + // Remember the referencing class. + ((MyAccessFixer)classVisitor).referencingClass = libraryClass; - // Make sure the access flags of the referenced class or class member, - // if any, are acceptable. - stringConstant.referencedClassAccept(this); - stringConstant.referencedMemberAccept(this); + // Start visiting and fixing the referenced classes and class members. + super.visitLibraryClass(libraryClass); } - public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + // Overridden methods for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { - // Check the bootstrap method. - invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this); + // Fix the referenced classes and class members. + super.visitProgramMember(programClass, programMethod); + + // Fix overridden or implemented methods higher up the hierarchy. + // We can ignore private and static methods and initializers. + if ((programMethod.getAccessFlags() & (ClassConstants.ACC_PRIVATE | + ClassConstants.ACC_STATIC)) == 0 && + !ClassUtil.isInitializer(programMethod.getName(programClass))) + { + programClass.hierarchyAccept(false, true, false, false, + new NamedMethodVisitor(programMethod.getName(programClass), + programMethod.getDescriptor(programClass), + new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | + ClassConstants.ACC_STATIC, + (MemberVisitor)classVisitor))); + } } - public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { - // Check the method reference. - clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); + // Fix the referenced classes and class members. + super.visitLibraryMember(libraryClass, libraryMethod); + + // Fix overridden or implemented methods higher up the hierarchy. + // We can ignore private and static methods and initializers. + if ((libraryMethod.getAccessFlags() & (ClassConstants.ACC_PRIVATE | + ClassConstants.ACC_STATIC)) == 0 && + !ClassUtil.isInitializer(libraryMethod.getName(libraryClass))) + { + libraryClass.hierarchyAccept(false, true, false, false, + new NamedMethodVisitor(libraryMethod.getName(libraryClass), + libraryMethod.getDescriptor(libraryClass), + new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | + ClassConstants.ACC_STATIC, + (MemberVisitor)classVisitor))); + } } - public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) - { - referencingClass = clazz; + // Overridden methods for ConstantVisitor. - // Remember the specified class, since it might be different from - // the referenced class that actually contains the class member. - clazz.constantPoolEntryAccept(refConstant.u2classIndex, referencedClassFinder); + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + // Fix the access flags of the referenced class, if any. + super.visitStringConstant(clazz, stringConstant); - // Make sure the access flags of the referenced class member are - // acceptable. - refConstant.referencedMemberAccept(this); + // Fix the access flags of the referenced class member, if any. + stringConstant.referencedMemberAccept((MemberVisitor)classVisitor); } - public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { - referencingClass = clazz; + // Fix the access flags of the referenced class. + super.visitAnyRefConstant(clazz, refConstant); - // Make sure the access flags of the referenced class are acceptable. - classConstant.referencedClassAccept(this); + // Fix the access flags of the referenced class member. + refConstant.referencedMemberAccept((MemberVisitor)classVisitor); } - // Implementations for ClassVisitor. + /** + * This ClassVisitor and MemberVisitor fixes the access flags of the + * classes and class members that it visits, relative to the referencing + * class. + */ + private static class MyAccessFixer + extends SimplifiedVisitor + implements ClassVisitor, + MemberVisitor + { + private Clazz referencingClass; - public void visitLibraryClass(LibraryClass libraryClass) {} + // Implementations for ClassVisitor. - public void visitProgramClass(ProgramClass programClass) - { - int currentAccessFlags = programClass.getAccessFlags(); - int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); + public void visitLibraryClass(LibraryClass libraryClass) {} - // Compute the required access level. - Clazz referencingClass = this.referencingClass; - int requiredAccessLevel = - inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : - AccessUtil.PUBLIC; - // Fix the class access flags if necessary. - if (currentAccessLevel < requiredAccessLevel) + public void visitProgramClass(ProgramClass programClass) { - programClass.u2accessFlags = - AccessUtil.replaceAccessFlags(currentAccessFlags, - AccessUtil.accessFlags(requiredAccessLevel)); + int currentAccessFlags = programClass.getAccessFlags(); + int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); + + // Compute the required access level. + int requiredAccessLevel = + inSamePackage(programClass, referencingClass) ? + AccessUtil.PACKAGE_VISIBLE : + AccessUtil.PUBLIC; + + // Fix the class access flags if necessary. + if (currentAccessLevel < requiredAccessLevel) + { + programClass.u2accessFlags = + AccessUtil.replaceAccessFlags(currentAccessFlags, + AccessUtil.accessFlags(requiredAccessLevel)); + } } - } - // Implementations for MemberVisitor. + // Implementations for MemberVisitor. - public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {} + public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {} - public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) - { - int currentAccessFlags = programMember.getAccessFlags(); - int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); - - // Compute the required access level. - int requiredAccessLevel = - programClass.equals(referencingClass) ? AccessUtil.PRIVATE : - inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : - referencedClass.extends_(referencingClass) && - referencingClass.extends_(programClass) ? AccessUtil.PROTECTED : - AccessUtil.PUBLIC; - - // Fix the class member access flags if necessary. - if (currentAccessLevel < requiredAccessLevel) + public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { - programMember.u2accessFlags = - AccessUtil.replaceAccessFlags(currentAccessFlags, - AccessUtil.accessFlags(requiredAccessLevel)); + int currentAccessFlags = programMember.getAccessFlags(); + int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); + + // Compute the required access level. + int requiredAccessLevel = + programClass.equals(referencingClass) ? AccessUtil.PRIVATE : + inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE : + programClass.extends_(referencingClass) && + referencingClass.extends_(programClass) ? AccessUtil.PROTECTED : + AccessUtil.PUBLIC; + + // Fix the class member access flags if necessary. + if (currentAccessLevel < requiredAccessLevel) + { + programMember.u2accessFlags = + AccessUtil.replaceAccessFlags(currentAccessFlags, + AccessUtil.accessFlags(requiredAccessLevel)); + } } - } - /** - * This ConstantVisitor returns the referenced class of the class constant - * that it visits. - */ - private class MyReferencedClassFinder - extends SimplifiedVisitor - implements ConstantVisitor - { - // Implementations for ConstantVisitor. - public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + // Small utility methods. + + /** + * Returns whether the two given classes are in the same package. + */ + private boolean inSamePackage(ProgramClass class1, Clazz class2) { - referencedClass = classConstant.referencedClass; + return ClassUtil.internalPackageName(class1.getName()).equals( + ClassUtil.internalPackageName(class2.getName())); } } - - - // Small utility methods. - - private boolean inSamePackage(ProgramClass class1, Clazz class2) - { - return ClassUtil.internalPackageName(class1.getName()).equals( - ClassUtil.internalPackageName(class2.getName())); - } } |