diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index d481c3acc9a..9dc8da3ae91 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -763,8 +763,7 @@ private void makeInvoke(InvokeNode insn, ICodeWriter code) throws CodegenExcepti case VIRTUAL: case INTERFACE: InsnArg arg = insn.getArg(0); - // FIXME: add 'this' for equals methods in scope - if (!arg.isThis()) { + if (needInvokeArg(arg)) { addArgDot(code, arg); } k++; @@ -799,6 +798,20 @@ private void makeInvoke(InvokeNode insn, ICodeWriter code) throws CodegenExcepti generateMethodArguments(code, insn, k, callMthNode); } + // FIXME: add 'this' for equals methods in scope + private boolean needInvokeArg(InsnArg arg) { + if (arg.isAnyThis()) { + if (arg.isThis()) { + return false; + } + ClassNode clsNode = mth.root().resolveClass(arg.getType()); + if (clsNode != null && clsNode.contains(AFlag.DONT_GENERATE)) { + return false; + } + } + return true; + } + private void makeInvokeLambda(ICodeWriter code, InvokeCustomNode customNode) throws CodegenException { if (customNode.isUseRef()) { makeRefLambda(code, customNode); diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java index bf16dd89c2d..ccb6e83687e 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java @@ -232,6 +232,27 @@ public boolean isThis() { return contains(AFlag.THIS); } + /** + * Return true for 'this' from other classes (often occur in anonymous classes) + */ + public boolean isAnyThis() { + if (contains(AFlag.THIS)) { + return true; + } + InsnNode wrappedInsn = unwrap(); + if (wrappedInsn != null && wrappedInsn.getType() == InsnType.IGET) { + return wrappedInsn.getArg(0).isAnyThis(); + } + return false; + } + + public InsnNode unwrap() { + if (isInsnWrap()) { + return ((InsnWrapArg) this).getWrapInsn(); + } + return null; + } + public boolean isConst() { return isLiteral() || (isInsnWrap() && ((InsnWrapArg) this).getWrapInsn().isConstInsn()); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java index 24b560803b4..ff774d90e96 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/rename/RenameVisitor.java @@ -97,7 +97,7 @@ private static void checkClassName(Deobfuscator deobfuscator, ClassNode cls, Jad // check inner classes names ClassInfo parentClass = classInfo.getParentClass(); while (parentClass != null) { - if (parentClass.getAliasShortName().equals(clsName)) { + if (parentClass.getAliasShortName().equals(newShortName)) { String clsAlias = deobfuscator.getClsAlias(cls); classInfo.changeShortName(clsAlias); cls.addAttr(new RenameReasonAttr(cls).append("collision with other inner class name")); diff --git a/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java b/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java index 62efd703c4b..b9cfb3d1314 100644 --- a/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java +++ b/jadx-core/src/test/java/jadx/tests/api/utils/assertj/JadxCodeAssertions.java @@ -74,6 +74,13 @@ public JadxCodeAssertions removeBlockComments() { return newCode; } + public JadxCodeAssertions removeLineComments() { + String code = actual.replaceAll("//.*(?!$)", ""); + JadxCodeAssertions newCode = new JadxCodeAssertions(code); + newCode.print(); + return newCode; + } + public JadxCodeAssertions print() { System.out.println("-----------------------------------------------------------"); System.out.println(actual); diff --git a/jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass18.java b/jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass18.java new file mode 100644 index 00000000000..8acbce26922 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass18.java @@ -0,0 +1,60 @@ +package jadx.tests.integration.inner; + +import org.junit.jupiter.api.Test; + +import jadx.api.CommentsLevel; +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestAnonymousClass18 extends IntegrationTest { + + @SuppressWarnings({ "Convert2Lambda", "Anonymous2MethodRef", "unused" }) + public static class TestCls { + + public interface Job { + void executeJob(); + } + + public void start() { + runJob(new Job() { + @Override + public void executeJob() { + runJob(new Job() { + @Override + public void executeJob() { + doSomething(); + } + }); + } + + private void doSomething() { + } + }); + } + + public static void runJob(Job job) { + } + } + + @Test + public void test() { + getArgs().setCommentsLevel(CommentsLevel.WARN); + assertThat(getClassNode(TestCls.class)) + .code() + .doesNotContain("AnonymousClass1.this") + .doesNotContain("class AnonymousClass1") + // .doesNotContain("TestAnonymousClass18$TestCls.runJob(") // TODO: ??? + .containsOne(indent() + "doSomething();"); + } + + @Test + public void testNoInline() { + getArgs().setInlineAnonymousClasses(false); + assertThat(getClassNode(TestCls.class)) + .code() + .containsOne("class AnonymousClass1 implements Job {") + .containsOne("class C00001 implements Job {") + .containsOne("AnonymousClass1.this.doSomething();"); + } +}