fix: don't inline constants into lambdas

This commit is contained in:
Skylot
2023-02-17 14:25:19 +00:00
parent c6ed117df6
commit ea37f3e9f7
3 changed files with 62 additions and 15 deletions
@@ -1016,9 +1016,14 @@ public class InsnGen {
int startArg = customNode.getHandleType() == MethodHandleType.INVOKE_STATIC ? 0 : 1; // skip 'this' arg
int callArg = 0;
for (int i = startArg; i < extArgsCount; i++) {
RegisterArg extArg = (RegisterArg) customNode.getArg(i);
RegisterArg callRegArg = callArgs.get(callArg++);
callRegArg.getSVar().setCodeVar(extArg.getSVar().getCodeVar());
InsnArg arg = customNode.getArg(i);
if (arg.isRegister()) {
RegisterArg extArg = (RegisterArg) arg;
RegisterArg callRegArg = callArgs.get(callArg++);
callRegArg.getSVar().setCodeVar(extArg.getSVar().getCodeVar());
} else {
throw new JadxRuntimeException("Unexpected argument type in lambda call: " + arg.getClass().getSimpleName());
}
}
code.add(" -> {");
code.incIndent();
@@ -1075,27 +1080,23 @@ public class InsnGen {
}
int argsCount = insn.getArgsCount();
code.add('(');
SkipMethodArgsAttr skipAttr = mthNode == null ? null : mthNode.get(AType.SKIP_MTH_ARGS);
boolean firstArg = true;
if (k < argsCount) {
for (int i = k; i < argsCount; i++) {
InsnArg arg = insn.getArg(i);
if (arg.contains(AFlag.SKIP_ARG)) {
if (arg.contains(AFlag.SKIP_ARG) || (skipAttr != null && skipAttr.isSkip(i - startArgNum))) {
continue;
}
int argOrigPos = i - startArgNum;
if (SkipMethodArgsAttr.isSkip(mthNode, argOrigPos)) {
continue;
}
if (!firstArg) {
code.add(", ");
} else {
if (firstArg) {
firstArg = false;
} else {
code.add(", ");
}
if (i == argsCount - 1 && processVarArg(code, insn, arg)) {
continue;
}
addArg(code, arg, false);
firstArg = false;
}
}
code.add(')');
@@ -16,6 +16,7 @@ import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.PrimitiveType;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.instructions.mods.ConstructorInsn;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.InsnNode;
@@ -178,7 +179,7 @@ public class ConstInlineVisitor extends AbstractVisitor {
List<RegisterArg> useList = new ArrayList<>(ssaVar.getUseList());
int replaceCount = 0;
for (RegisterArg arg : useList) {
if (canInline(arg) && replaceArg(mth, arg, constArg, constInsn)) {
if (canInline(mth, arg) && replaceArg(mth, arg, constArg, constInsn)) {
replaceCount++;
}
}
@@ -204,8 +205,8 @@ public class ConstInlineVisitor extends AbstractVisitor {
}
@SuppressWarnings("RedundantIfStatement")
private static boolean canInline(RegisterArg arg) {
if (arg.contains(AFlag.DONT_INLINE_CONST)) {
private static boolean canInline(MethodNode mth, RegisterArg arg) {
if (arg.contains(AFlag.DONT_INLINE_CONST) || arg.contains(AFlag.DONT_INLINE)) {
return false;
}
InsnNode parentInsn = arg.getParentInsn();
@@ -219,6 +220,14 @@ public class ConstInlineVisitor extends AbstractVisitor {
// don't inline vars used in finally block
return false;
}
if (parentInsn.getType() == InsnType.CONSTRUCTOR) {
// don't inline into anonymous call if it can be inlined later
ConstructorInsn ctrInsn = (ConstructorInsn) parentInsn;
MethodNode ctrMth = mth.root().getMethodUtils().resolveMethod(ctrInsn);
if (ctrMth != null && ctrMth.contains(AFlag.METHOD_CANDIDATE_FOR_INLINE)) {
return false;
}
}
return true;
}
@@ -0,0 +1,37 @@
package jadx.tests.integration.java8;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jadx.tests.api.IntegrationTest;
import jadx.tests.api.extensions.profiles.TestProfile;
import jadx.tests.api.extensions.profiles.TestWithProfiles;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestLambdaExtVar2 extends IntegrationTest {
public static class TestCls {
public void test(List<String> list) {
String space = " ";
list.removeIf(s -> s.equals(space) || s.contains(space));
}
public void check() {
List<String> list = new ArrayList<>(Arrays.asList("a", " ", "b", "r "));
test(list);
assertThat(list).isEqualTo(Arrays.asList("a", "b"));
}
}
@TestWithProfiles({ TestProfile.DX_J8, TestProfile.D8_J11, TestProfile.JAVA11 })
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("lambda$")
.containsOne("String space = \" \";")
.containsOne("s.equals(space) || s.contains(space)");
}
}