未验证 提交 87e0e5bf 编写于 作者: S Skylot

fix: correct inline/merge with overriden bridge method (#1580)

上级 e4c2d6cf
...@@ -32,6 +32,22 @@ public class NodeDeclareRef implements ICodeAnnotation { ...@@ -32,6 +32,22 @@ public class NodeDeclareRef implements ICodeAnnotation {
return AnnType.DECLARATION; 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 @Override
public String toString() { public String toString() {
return "NodeDeclareRef{" + node + '}'; return "NodeDeclareRef{" + node + '}';
......
...@@ -26,6 +26,7 @@ import jadx.core.dex.attributes.AType; ...@@ -26,6 +26,7 @@ import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.JadxError; import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JumpInfo; import jadx.core.dex.attributes.nodes.JumpInfo;
import jadx.core.dex.attributes.nodes.MethodOverrideAttr; import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
import jadx.core.dex.attributes.nodes.MethodReplaceAttr;
import jadx.core.dex.info.AccessInfo; import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.ConstStringNode; import jadx.core.dex.instructions.ConstStringNode;
import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.IfNode;
...@@ -144,8 +145,9 @@ public class MethodGen { ...@@ -144,8 +145,9 @@ public class MethodGen {
} else { } else {
classGen.useType(code, mth.getReturnType()); classGen.useType(code, mth.getReturnType());
code.add(' '); code.add(' ');
code.attachDefinition(mth); MethodNode defMth = getMethodForDefinition();
code.add(mth.getAlias()); code.attachDefinition(defMth);
code.add(defMth.getAlias());
} }
code.add('('); code.add('(');
...@@ -178,6 +180,14 @@ public class MethodGen { ...@@ -178,6 +180,14 @@ public class MethodGen {
return true; 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) { private void addOverrideAnnotation(ICodeWriter code, MethodNode mth) {
MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE); MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE);
if (overrideAttr == null) { if (overrideAttr == null) {
......
...@@ -10,6 +10,7 @@ import java.util.Objects; ...@@ -10,6 +10,7 @@ import java.util.Objects;
import jadx.api.plugins.input.data.AccessFlags; import jadx.api.plugins.input.data.AccessFlags;
import jadx.core.Consts; import jadx.core.Consts;
import jadx.core.dex.attributes.AFlag; 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.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.MethodReplaceAttr; import jadx.core.dex.attributes.nodes.MethodReplaceAttr;
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr; import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
...@@ -281,6 +282,9 @@ public class ClassModifier extends AbstractVisitor { ...@@ -281,6 +282,9 @@ public class ClassModifier extends AbstractVisitor {
if (!Objects.equals(wrappedMth.getAlias(), alias)) { if (!Objects.equals(wrappedMth.getAlias(), alias)) {
wrappedMth.getMethodInfo().setAlias(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; return true;
} }
......
...@@ -8,7 +8,6 @@ import org.assertj.core.api.Assertions; ...@@ -8,7 +8,6 @@ import org.assertj.core.api.Assertions;
import jadx.api.ICodeInfo; import jadx.api.ICodeInfo;
import jadx.api.metadata.ICodeAnnotation; import jadx.api.metadata.ICodeAnnotation;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.ICodeNode;
import jadx.tests.api.IntegrationTest; import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
...@@ -58,11 +57,12 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA ...@@ -58,11 +57,12 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA
return this; return this;
} }
public void checkCodeAnnotationFor(String refStr, ICodeNode node) { public JadxClassNodeAssertions checkCodeAnnotationFor(String refStr, ICodeAnnotation node) {
checkCodeAnnotationFor(refStr, 0, 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(); ICodeInfo code = actual.getCode();
int codePos = code.getCodeStr().indexOf(refStr); int codePos = code.getCodeStr().indexOf(refStr);
assertThat(codePos).describedAs("String '%s' not found", refStr).isNotEqualTo(-1); assertThat(codePos).describedAs("String '%s' not found", refStr).isNotEqualTo(-1);
...@@ -70,9 +70,10 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA ...@@ -70,9 +70,10 @@ public class JadxClassNodeAssertions extends AbstractObjectAssert<JadxClassNodeA
for (Map.Entry<Integer, ICodeAnnotation> entry : code.getCodeMetadata().getAsMap().entrySet()) { for (Map.Entry<Integer, ICodeAnnotation> entry : code.getCodeMetadata().getAsMap().entrySet()) {
if (entry.getKey() == refPos) { if (entry.getKey() == refPos) {
Assertions.assertThat(entry.getValue()).isEqualTo(node); Assertions.assertThat(entry.getValue()).isEqualTo(node);
return; return this;
} }
} }
fail("Annotation for reference string: '%s' at position %d not found", refStr, refPos); fail("Annotation for reference string: '%s' at position %d not found", refStr, refPos);
return this;
} }
} }
...@@ -56,8 +56,6 @@ public class TestGenericsMthOverride extends IntegrationTest { ...@@ -56,8 +56,6 @@ public class TestGenericsMthOverride extends IntegrationTest {
assertThat(code, containsOne("public Y method(Exception x) {")); assertThat(code, containsOne("public Y method(Exception x) {"));
assertThat(code, containsOne("public Object method(Object x) {")); assertThat(code, containsOne("public Object method(Object x) {"));
assertThat(code, countString(3, "@Override")); assertThat(code, countString(4, "@Override"));
// TODO: @Override missing for class C
// assertThat(code, countString(4, "@Override"));
} }
} }
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)");
}
}
.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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册