diff --git a/src/main/java/proguard/classfile/attribute/visitor/ClassConstantToClassVisitor.java b/src/main/java/proguard/classfile/attribute/visitor/ClassConstantToClassVisitor.java new file mode 100644 index 000000000..a232e4880 --- /dev/null +++ b/src/main/java/proguard/classfile/attribute/visitor/ClassConstantToClassVisitor.java @@ -0,0 +1,53 @@ +/* + * ProGuardCORE -- library to process Java bytecode. + * + * Copyright (c) 2002-2022 Guardsquare NV + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package proguard.classfile.attribute.visitor; + +import proguard.classfile.Clazz; +import proguard.classfile.constant.ClassConstant; +import proguard.classfile.constant.Constant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.visitor.ClassVisitor; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This {@link ConstantVisitor} lets a given {@link ClassVisitor} visit the classes that are referenced by the visited + * class constants. + * + * @author Joren Van Hecke + */ +public class ClassConstantToClassVisitor implements ConstantVisitor +{ + + private final ClassVisitor classVisitor; + + public ClassConstantToClassVisitor(ClassVisitor classVisitor) + { + this.classVisitor = classVisitor; + } + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + @Override + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + if (this.classVisitor != null && classConstant.referencedClass != null) + { + classConstant.referencedClass.accept(this.classVisitor); + } + } +} diff --git a/src/main/java/proguard/classfile/editor/InnerClassRemover.java b/src/main/java/proguard/classfile/editor/InnerClassRemover.java new file mode 100644 index 000000000..554fcc150 --- /dev/null +++ b/src/main/java/proguard/classfile/editor/InnerClassRemover.java @@ -0,0 +1,77 @@ +/* + * ProGuardCORE -- library to process Java bytecode. + * + * Copyright (c) 2002-2022 Guardsquare NV + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package proguard.classfile.editor; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import proguard.classfile.Clazz; +import proguard.classfile.attribute.Attribute; +import proguard.classfile.attribute.InnerClassesAttribute; +import proguard.classfile.attribute.InnerClassesInfo; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.attribute.visitor.InnerClassesInfoVisitor; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * This {@link AttributeVisitor} and {@link InnerClassesInfoVisitor} removes a given {@link Clazz} from all visited + * {@link InnerClassesAttribute}s. + * + * @author Joren Van Hecke + */ +public class InnerClassRemover implements AttributeVisitor, InnerClassesInfoVisitor +{ + private final Clazz classToBeRemoved; + private final Set innerClassesEntriesToBeRemoved = new HashSet<>(); + private static final Logger logger = LogManager.getLogger(InnerClassRemover.class); + + public InnerClassRemover(Clazz clazz) + { + this.classToBeRemoved = clazz; + } + + @Override + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + @Override + public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) + { + innerClassesAttribute.innerClassEntriesAccept(clazz, this); + InnerClassesAttributeEditor editor = new InnerClassesAttributeEditor(innerClassesAttribute); + logger.trace("{} inner class entries are removed from class {}", + innerClassesEntriesToBeRemoved.size(), clazz); + for (InnerClassesInfo entry : innerClassesEntriesToBeRemoved) + { + editor.removeInnerClassesInfo(entry); + } + } + + @Override + public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) + { + String innerClassName = clazz.getClassName(innerClassesInfo.u2innerClassIndex); + if (Objects.equals(innerClassName, this.classToBeRemoved.getName())) + { + logger.trace("Removing inner classes entry of class {} enqueued to be removed from class {}", + innerClassName, clazz); + innerClassesEntriesToBeRemoved.add(innerClassesInfo); + } + } +} diff --git a/src/main/java/proguard/classfile/kotlin/KotlinConstants.java b/src/main/java/proguard/classfile/kotlin/KotlinConstants.java index d02f55791..603f5408b 100644 --- a/src/main/java/proguard/classfile/kotlin/KotlinConstants.java +++ b/src/main/java/proguard/classfile/kotlin/KotlinConstants.java @@ -43,6 +43,7 @@ public class KotlinConstants public static final String TYPE_KOTLIN_METADATA = "Lkotlin/Metadata;"; public static final String NAME_KOTLIN_ANY = "kotlin/Any"; public static final String NAME_KOTLIN_UNIT = "kotlin/Unit"; + public static final String TYPE_KOTLIN_UNIT = "Lkotlin/Unit;"; public static final String NAME_KOTLIN_ENUM = "kotlin/Enum"; public static final String NAME_KOTLIN_FUNCTION = "kotlin/Function"; // kotlin/Function and also kotlin/FunctionN public static final String NAME_KOTLIN_EXTENSION_FUNCTION = "kotlin/ExtensionFunctionType"; diff --git a/src/main/java/proguard/classfile/visitor/ClassReferenceFinder.java b/src/main/java/proguard/classfile/visitor/ClassReferenceFinder.java new file mode 100644 index 000000000..355c65893 --- /dev/null +++ b/src/main/java/proguard/classfile/visitor/ClassReferenceFinder.java @@ -0,0 +1,32 @@ +package proguard.classfile.visitor; + +import proguard.classfile.Clazz; +import proguard.classfile.constant.ClassConstant; +import proguard.classfile.constant.Constant; +import proguard.classfile.constant.visitor.ConstantVisitor; + +public class ClassReferenceFinder implements ConstantVisitor +{ + private final Clazz referencedClass; + private boolean classIsReferenced = false; + + public ClassReferenceFinder(Clazz referencedClass) + { + this.referencedClass = referencedClass; + } + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + if (classConstant.referencedClass != null && classConstant.referencedClass.equals(referencedClass)) + { + this.classIsReferenced = true; + } + } + + public boolean classReferenceFound() + { + return this.classIsReferenced; + } +} diff --git a/src/main/java/proguard/classfile/visitor/CodeSizeCounter.java b/src/main/java/proguard/classfile/visitor/CodeSizeCounter.java new file mode 100644 index 000000000..61b821b34 --- /dev/null +++ b/src/main/java/proguard/classfile/visitor/CodeSizeCounter.java @@ -0,0 +1,29 @@ +package proguard.classfile.visitor; + +import proguard.classfile.Clazz; +import proguard.classfile.Method; +import proguard.classfile.attribute.Attribute; +import proguard.classfile.attribute.CodeAttribute; +import proguard.classfile.attribute.visitor.AttributeVisitor; + +public class CodeSizeCounter +implements AttributeVisitor +{ + private int totalCodeSize = 0; + + // Implementations for AttributeVisitor + + @Override + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + @Override + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + totalCodeSize += codeAttribute.u4codeLength; + } + + public int getCount() + { + return totalCodeSize; + } +} diff --git a/src/main/java/proguard/classfile/visitor/DescriptorTypeUpdater.java b/src/main/java/proguard/classfile/visitor/DescriptorTypeUpdater.java new file mode 100644 index 000000000..aa6cf4ea3 --- /dev/null +++ b/src/main/java/proguard/classfile/visitor/DescriptorTypeUpdater.java @@ -0,0 +1,25 @@ +package proguard.classfile.visitor; + +import proguard.classfile.Clazz; +import proguard.classfile.constant.Constant; +import proguard.classfile.constant.Utf8Constant; +import proguard.classfile.constant.visitor.ConstantVisitor; + +public class DescriptorTypeUpdater implements ConstantVisitor +{ + private final String originalType; + private final String replacingType; + public DescriptorTypeUpdater(String originalType, String replacingType) + { + this.originalType = originalType; + this.replacingType = replacingType; + } + + @Override + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + @Override + public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { + utf8Constant.setString(utf8Constant.getString().replace(originalType, replacingType)); + } +} diff --git a/src/test/kotlin/testutils/MatchDetector.kt b/src/test/kotlin/testutils/MatchDetector.kt new file mode 100644 index 000000000..0e722f8be --- /dev/null +++ b/src/test/kotlin/testutils/MatchDetector.kt @@ -0,0 +1,28 @@ +package testutils + +import proguard.classfile.Clazz +import proguard.classfile.Method +import proguard.classfile.attribute.CodeAttribute +import proguard.classfile.instruction.Instruction +import proguard.classfile.instruction.visitor.InstructionVisitor +import proguard.classfile.util.InstructionSequenceMatcher + +class MatchDetector(val matcher: InstructionSequenceMatcher, vararg val arguments: Int) : InstructionVisitor { + var matchIsFound = false + var matchedArguments = IntArray(arguments.size) + + override fun visitAnyInstruction( + clazz: Clazz, + method: Method, + codeAttribute: CodeAttribute, + offset: Int, + instruction: Instruction + ) { + println(instruction.toString(clazz, offset)) + instruction.accept(clazz, method, codeAttribute, offset, matcher) + if (matcher.isMatching()) { + matchIsFound = true + matchedArguments = matcher.matchedArguments(arguments) + } + } +}