summaryrefslogtreecommitdiffstats
path: root/src/proguard/classfile/editor/AccessFixer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/classfile/editor/AccessFixer.java')
-rw-r--r--src/proguard/classfile/editor/AccessFixer.java234
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()));
- }
}