aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/java/proguard/proguard5.3.3/src/proguard/classfile/editor/MemberReferenceFixer.java
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/java/proguard/proguard5.3.3/src/proguard/classfile/editor/MemberReferenceFixer.java')
-rw-r--r--third_party/java/proguard/proguard5.3.3/src/proguard/classfile/editor/MemberReferenceFixer.java447
1 files changed, 447 insertions, 0 deletions
diff --git a/third_party/java/proguard/proguard5.3.3/src/proguard/classfile/editor/MemberReferenceFixer.java b/third_party/java/proguard/proguard5.3.3/src/proguard/classfile/editor/MemberReferenceFixer.java
new file mode 100644
index 0000000000..107205c572
--- /dev/null
+++ b/third_party/java/proguard/proguard5.3.3/src/proguard/classfile/editor/MemberReferenceFixer.java
@@ -0,0 +1,447 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare
+ *
+ * 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.attribute.annotation.visitor.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassVisitor fixes constant pool field and method references to fields
+ * and methods whose names or descriptors have changed.
+ *
+ * @author Eric Lafortune
+ */
+public class MemberReferenceFixer
+extends SimplifiedVisitor
+implements ClassVisitor,
+ ConstantVisitor,
+ MemberVisitor,
+ AttributeVisitor,
+ AnnotationVisitor,
+ ElementValueVisitor
+{
+ private static final boolean DEBUG = false;
+
+
+ private final StackSizeUpdater stackSizeUpdater = new StackSizeUpdater();
+
+ // Parameter for the visitor methods.
+ private int constantIndex;
+
+ // Return values for the visitor methods.
+ private boolean isInterfaceMethod;
+ private boolean stackSizesMayHaveChanged;
+
+
+ // Implementations for ClassVisitor.
+
+ public void visitProgramClass(ProgramClass programClass)
+ {
+ stackSizesMayHaveChanged = false;
+
+ // Fix the constant pool entries.
+ for (int index = 1; index < programClass.u2constantPoolCount; index++)
+ {
+ Constant constant = programClass.constantPool[index];
+ if (constant != null)
+ {
+ // Fix the entry, replacing it entirely if needed.
+ this.constantIndex = index;
+
+ constant.accept(programClass, this);
+ }
+ }
+
+ // Fix the class members.
+ programClass.fieldsAccept(this);
+ programClass.methodsAccept(this);
+
+ // Fix the attributes.
+ programClass.attributesAccept(this);
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitAnyConstant(Clazz clazz, Constant constant) {}
+
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ // Does the string refer to a class member, due to a
+ // Class.get[Declared]{Field,Method} construct?
+ Member referencedMember = stringConstant.referencedMember;
+ if (referencedMember != null)
+ {
+ Clazz referencedClass = stringConstant.referencedClass;
+
+ // Does it have a new name?
+ String newName = referencedMember.getName(referencedClass);
+
+ if (!stringConstant.getString(clazz).equals(newName))
+ {
+ if (DEBUG)
+ {
+ debug(clazz, stringConstant, referencedClass, referencedMember);
+ }
+
+ // Update the name.
+ stringConstant.u2stringIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newName);
+ }
+ }
+ }
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ // Do we know the referenced field?
+ Member referencedMember = fieldrefConstant.referencedMember;
+ if (referencedMember != null)
+ {
+ Clazz referencedClass = fieldrefConstant.referencedClass;
+
+ // Does it have a new name or type?
+ String newName = referencedMember.getName(referencedClass);
+ String newType = referencedMember.getDescriptor(referencedClass);
+
+ if (!fieldrefConstant.getName(clazz).equals(newName) ||
+ !fieldrefConstant.getType(clazz).equals(newType))
+ {
+ if (DEBUG)
+ {
+ debug(clazz, fieldrefConstant, referencedClass, referencedMember);
+ }
+
+ // Update the name and type index.
+ fieldrefConstant.u2nameAndTypeIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType);
+ }
+ }
+ }
+
+
+ public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
+ {
+ // Do we know the referenced interface method?
+ Member referencedMember = interfaceMethodrefConstant.referencedMember;
+ if (referencedMember != null)
+ {
+ Clazz referencedClass = interfaceMethodrefConstant.referencedClass;
+
+ // Does it have a new name or type?
+ String newName = referencedMember.getName(referencedClass);
+ String newType = referencedMember.getDescriptor(referencedClass);
+
+ if (!interfaceMethodrefConstant.getName(clazz).equals(newName) ||
+ !interfaceMethodrefConstant.getType(clazz).equals(newType))
+ {
+ if (DEBUG)
+ {
+ debug(clazz, interfaceMethodrefConstant, referencedClass, referencedMember);
+ }
+
+ // Update the name and type index.
+ interfaceMethodrefConstant.u2nameAndTypeIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType);
+
+ // Remember that the stack sizes of the methods in this class
+ // may have changed.
+ stackSizesMayHaveChanged = true;
+ }
+
+ // Check if this is an interface method.
+ isInterfaceMethod = true;
+ clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2classIndex, this);
+
+ // Has the method become a non-interface method?
+ if (!isInterfaceMethod)
+ {
+ if (DEBUG)
+ {
+ System.out.println("MemberReferenceFixer:");
+ System.out.println(" Class file = "+clazz.getName());
+ System.out.println(" Ref class = "+referencedClass.getName());
+ System.out.println(" Ref method = "+interfaceMethodrefConstant.getName(clazz)+interfaceMethodrefConstant.getType(clazz));
+ System.out.println(" -> ordinary method");
+ }
+
+ // Replace the interface method reference by a method reference.
+ ((ProgramClass)clazz).constantPool[this.constantIndex] =
+ new MethodrefConstant(interfaceMethodrefConstant.u2classIndex,
+ interfaceMethodrefConstant.u2nameAndTypeIndex,
+ referencedClass,
+ referencedMember);
+ }
+ }
+ }
+
+
+ public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ {
+ // Do we know the referenced method?
+ Member referencedMember = methodrefConstant.referencedMember;
+ if (referencedMember != null)
+ {
+ Clazz referencedClass = methodrefConstant.referencedClass;
+
+ // Does it have a new name or type?
+ String newName = referencedMember.getName(referencedClass);
+ String newType = referencedMember.getDescriptor(referencedClass);
+
+ if (!methodrefConstant.getName(clazz).equals(newName) ||
+ !methodrefConstant.getType(clazz).equals(newType))
+ {
+ if (DEBUG)
+ {
+ debug(clazz, methodrefConstant, referencedClass, referencedMember);
+ }
+
+ // Update the name and type index.
+ methodrefConstant.u2nameAndTypeIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, newType);
+
+ // Remember that the stack sizes of the methods in this class
+ // may have changed.
+ stackSizesMayHaveChanged = true;
+ }
+
+ // Check if this is an interface method.
+ isInterfaceMethod = false;
+ clazz.constantPoolEntryAccept(methodrefConstant.u2classIndex, this);
+
+ // Has the method become an interface method?
+ if (isInterfaceMethod)
+ {
+ if (DEBUG)
+ {
+ System.out.println("MemberReferenceFixer:");
+ System.out.println(" Class file = "+clazz.getName());
+ System.out.println(" Ref class = "+referencedClass.getName());
+ System.out.println(" Ref method = "+methodrefConstant.getName(clazz)+methodrefConstant.getType(clazz));
+ System.out.println(" -> interface method");
+ }
+
+ // Replace the method reference by an interface method reference.
+ ((ProgramClass)clazz).constantPool[this.constantIndex] =
+ new InterfaceMethodrefConstant(methodrefConstant.u2classIndex,
+ methodrefConstant.u2nameAndTypeIndex,
+ referencedClass,
+ referencedMember);
+ }
+ }
+ }
+
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ // Check if this class entry is an array type.
+ if (ClassUtil.isInternalArrayType(classConstant.getName(clazz)))
+ {
+ isInterfaceMethod = false;
+ }
+ else
+ {
+ // Check if this class entry refers to an interface class.
+ Clazz referencedClass = classConstant.referencedClass;
+ if (referencedClass != null)
+ {
+ isInterfaceMethod = (referencedClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) != 0;
+ }
+ }
+ }
+
+
+ // Implementations for MemberVisitor.
+
+ public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
+ {
+ // Fix the attributes.
+ programMember.attributesAccept(programClass, this);
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
+ {
+ Member referencedMember = enclosingMethodAttribute.referencedMethod;
+ if (referencedMember != null)
+ {
+ Clazz referencedClass = enclosingMethodAttribute.referencedClass;
+
+ // Does it have a new name or type?
+ String newName = referencedMember.getName(referencedClass);
+ String newType = referencedMember.getDescriptor(referencedClass);
+
+ if (!enclosingMethodAttribute.getName(clazz).equals(newName) ||
+ !enclosingMethodAttribute.getType(clazz).equals(newType))
+ {
+ // Update the name and type index.
+ enclosingMethodAttribute.u2nameAndTypeIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName,
+ newType);
+ }
+ }
+ }
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ // Recompute the maximum stack size if necessary.
+ if (stackSizesMayHaveChanged)
+ {
+ stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
+ }
+
+ // Fix the nested attributes.
+ codeAttribute.attributesAccept(clazz, method, this);
+ }
+
+
+ public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
+ {
+ // Fix the annotations.
+ annotationsAttribute.annotationsAccept(clazz, this);
+ }
+
+
+ public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
+ {
+ // Fix the annotations.
+ parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
+ }
+
+
+ public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
+ {
+ // Fix the annotation.
+ annotationDefaultAttribute.defaultValueAccept(clazz, this);
+ }
+
+
+ // Implementations for AnnotationVisitor.
+
+ public void visitAnnotation(Clazz clazz, Annotation annotation)
+ {
+ // Fix the element values.
+ annotation.elementValuesAccept(clazz, this);
+ }
+
+
+ // Implementations for ElementValueVisitor.
+
+ public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
+ {
+ fixElementValue(clazz, annotation, constantElementValue);
+ }
+
+
+ public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+ {
+ fixElementValue(clazz, annotation, enumConstantElementValue);
+ }
+
+
+ public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
+ {
+ fixElementValue(clazz, annotation, classElementValue);
+ }
+
+
+ public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
+ {
+ fixElementValue(clazz, annotation, annotationElementValue);
+
+ // Fix the annotation.
+ annotationElementValue.annotationAccept(clazz, this);
+ }
+
+
+ public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
+ {
+ fixElementValue(clazz, annotation, arrayElementValue);
+
+ // Fix the element values.
+ arrayElementValue.elementValuesAccept(clazz, annotation, this);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Fixes the method reference of the element value, if any.
+ */
+ private void fixElementValue(Clazz clazz,
+ Annotation annotation,
+ ElementValue elementValue)
+ {
+ // Do we know the referenced method?
+ Member referencedMember = elementValue.referencedMethod;
+ if (referencedMember != null)
+ {
+ // Does it have a new name or type?
+ String methodName = elementValue.getMethodName(clazz);
+ String newMethodName = referencedMember.getName(elementValue.referencedClass);
+
+ if (!methodName.equals(newMethodName))
+ {
+ // Update the element name index.
+ elementValue.u2elementNameIndex =
+ new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newMethodName);
+ }
+ }
+ }
+
+
+ private void debug(Clazz clazz,
+ StringConstant stringConstant,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ System.out.println("MemberReferenceFixer:");
+ System.out.println(" ["+clazz.getName()+"]: String ["+
+ stringConstant.getString(clazz)+"] -> ["+
+ referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]");
+ }
+
+
+ private void debug(Clazz clazz,
+ RefConstant refConstant,
+ Clazz referencedClass,
+ Member referencedMember)
+ {
+ System.out.println("MemberReferenceFixer:");
+ System.out.println(" ["+clazz.getName()+"]: ["+
+ refConstant.getClassName(clazz)+"."+refConstant.getName(clazz)+" "+refConstant.getType(clazz)+"] -> ["+
+ referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]");
+ }
+}