fix: correct inline/merge with overriden bridge method (#1580)
This commit is contained in:
@@ -32,6 +32,22 @@ public class NodeDeclareRef implements ICodeAnnotation {
|
||||
return AnnType.DECLARATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof NodeDeclareRef)) {
|
||||
return false;
|
||||
}
|
||||
return node.equals(((NodeDeclareRef) o).node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return node.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NodeDeclareRef{" + node + '}';
|
||||
|
||||
@@ -26,6 +26,7 @@ import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.JadxError;
|
||||
import jadx.core.dex.attributes.nodes.JumpInfo;
|
||||
import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
|
||||
import jadx.core.dex.attributes.nodes.MethodReplaceAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.instructions.ConstStringNode;
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
@@ -144,8 +145,9 @@ public class MethodGen {
|
||||
} else {
|
||||
classGen.useType(code, mth.getReturnType());
|
||||
code.add(' ');
|
||||
code.attachDefinition(mth);
|
||||
code.add(mth.getAlias());
|
||||
MethodNode defMth = getMethodForDefinition();
|
||||
code.attachDefinition(defMth);
|
||||
code.add(defMth.getAlias());
|
||||
}
|
||||
code.add('(');
|
||||
|
||||
@@ -178,6 +180,14 @@ public class MethodGen {
|
||||
return true;
|
||||
}
|
||||
|
||||
private MethodNode getMethodForDefinition() {
|
||||
MethodReplaceAttr replaceAttr = mth.get(AType.METHOD_REPLACE);
|
||||
if (replaceAttr != null) {
|
||||
return replaceAttr.getReplaceMth();
|
||||
}
|
||||
return mth;
|
||||
}
|
||||
|
||||
private void addOverrideAnnotation(ICodeWriter code, MethodNode mth) {
|
||||
MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE);
|
||||
if (overrideAttr == null) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.Objects;
|
||||
import jadx.api.plugins.input.data.AccessFlags;
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
|
||||
import jadx.core.dex.attributes.nodes.MethodReplaceAttr;
|
||||
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
|
||||
@@ -281,6 +282,9 @@ public class ClassModifier extends AbstractVisitor {
|
||||
if (!Objects.equals(wrappedMth.getAlias(), alias)) {
|
||||
wrappedMth.getMethodInfo().setAlias(alias);
|
||||
}
|
||||
wrappedMth.addAttr(new MethodReplaceAttr(mth));
|
||||
wrappedMth.copyAttributeFrom(mth, AType.METHOD_OVERRIDE);
|
||||
wrappedMth.addDebugComment("Method merged with bridge method");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.assertj.core.api.Assertions;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.ICodeNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
@@ -58,11 +57,12 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA
|
||||
return this;
|
||||
}
|
||||
|
||||
public void checkCodeAnnotationFor(String refStr, ICodeNode node) {
|
||||
public JadxClassNodeAssertions checkCodeAnnotationFor(String refStr, ICodeAnnotation node) {
|
||||
checkCodeAnnotationFor(refStr, 0, node);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void checkCodeAnnotationFor(String refStr, int refOffset, ICodeNode node) {
|
||||
public JadxClassNodeAssertions checkCodeAnnotationFor(String refStr, int refOffset, ICodeAnnotation node) {
|
||||
ICodeInfo code = actual.getCode();
|
||||
int codePos = code.getCodeStr().indexOf(refStr);
|
||||
assertThat(codePos).describedAs("String '%s' not found", refStr).isNotEqualTo(-1);
|
||||
@@ -70,9 +70,10 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA
|
||||
for (Map.Entry<Integer, ICodeAnnotation> entry : code.getCodeMetadata().getAsMap().entrySet()) {
|
||||
if (entry.getKey() == refPos) {
|
||||
Assertions.assertThat(entry.getValue()).isEqualTo(node);
|
||||
return;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
fail("Annotation for reference string: '%s' at position %d not found", refStr, refPos);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -56,8 +56,6 @@ public class TestGenericsMthOverride extends IntegrationTest {
|
||||
assertThat(code, containsOne("public Y method(Exception x) {"));
|
||||
assertThat(code, containsOne("public Object method(Object x) {"));
|
||||
|
||||
assertThat(code, countString(3, "@Override"));
|
||||
// TODO: @Override missing for class C
|
||||
// assertThat(code, countString(4, "@Override"));
|
||||
assertThat(code, countString(4, "@Override"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package jadx.tests.integration.inline;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.api.metadata.annotations.NodeDeclareRef;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestOverrideBridgeMerge extends SmaliTest {
|
||||
|
||||
public static class TestCls implements Function<String, Integer> {
|
||||
@Override
|
||||
public /* bridge */ /* synthetic */ Integer apply(String str) {
|
||||
return test(str);
|
||||
}
|
||||
|
||||
public Integer test(String str) {
|
||||
return str.length();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("Integer test(String str) {"); // not inlined
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmali() {
|
||||
ClassNode cls = getClassNodeFromSmali();
|
||||
ICodeAnnotation mthDef = new NodeDeclareRef(getMethod(cls, "apply"));
|
||||
assertThat(cls)
|
||||
.checkCodeAnnotationFor("apply(String str) {", mthDef)
|
||||
.code()
|
||||
.containsOne("@Override")
|
||||
.containsOne("public Integer apply(String str) {")
|
||||
.doesNotContain("test(String str)");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
.class public Linline/TestOverrideBridgeMerge;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.implements Ljava/util/function/Function;
|
||||
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/lang/Object;",
|
||||
"Ljava/util/function/Function",
|
||||
"<",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/Integer;",
|
||||
">;"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
.method public constructor <init>()V
|
||||
.registers 1
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public bridge synthetic apply(Ljava/lang/Object;)Ljava/lang/Object;
|
||||
.registers 3
|
||||
check-cast p1, Ljava/lang/String;
|
||||
invoke-virtual {p0, p1}, Linline/TestOverrideBridgeMerge;->test(Ljava/lang/String;)Ljava/lang/Integer;
|
||||
move-result-object v0
|
||||
return-object v0
|
||||
.end method
|
||||
|
||||
.method public test(Ljava/lang/String;)Ljava/lang/Integer;
|
||||
.registers 3
|
||||
.param p1, "str" # Ljava/lang/String;
|
||||
invoke-virtual {p1}, Ljava/lang/String;->length()I
|
||||
move-result v0
|
||||
invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
|
||||
move-result-object v0
|
||||
return-object v0
|
||||
.end method
|
||||
Reference in New Issue
Block a user