core: fix wildcard type in iterable loop
This commit is contained in:
@@ -16,7 +16,6 @@ import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
@@ -232,14 +231,23 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
}
|
||||
List<InsnNode> toSkip = new LinkedList<InsnNode>();
|
||||
RegisterArg iterVar = nextCall.getResult();
|
||||
if (iterVar == null) {
|
||||
return false;
|
||||
}
|
||||
if (nextCall.contains(AFlag.WRAPPED)) {
|
||||
InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, nextCall);
|
||||
if (wrapArg != null && wrapArg.getParentInsn() != null) {
|
||||
InsnNode parentInsn = wrapArg.getParentInsn();
|
||||
if (parentInsn.getType() != InsnType.CHECK_CAST) {
|
||||
if (!fixIterableType(mth, iterableArg, iterVar)) {
|
||||
return false;
|
||||
}
|
||||
parentInsn.replaceArg(wrapArg, iterVar);
|
||||
} else {
|
||||
iterVar = parentInsn.getResult();
|
||||
if (iterVar == null || !fixIterableType(mth, iterableArg, iterVar)) {
|
||||
return false;
|
||||
}
|
||||
InsnArg castArg = BlockUtils.searchWrappedInsnParent(mth, parentInsn);
|
||||
if (castArg != null && castArg.getParentInsn() != null) {
|
||||
castArg.getParentInsn().replaceArg(castArg, iterVar);
|
||||
@@ -255,9 +263,6 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
} else {
|
||||
toSkip.add(nextCall);
|
||||
}
|
||||
if (iterVar == null || !fixIterableType(mth.dex(), iterableArg, iterVar)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assignInsn.add(AFlag.SKIP);
|
||||
for (InsnNode insnNode : toSkip) {
|
||||
@@ -267,7 +272,7 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean fixIterableType(DexNode dex, InsnArg iterableArg, RegisterArg iterVar) {
|
||||
private static boolean fixIterableType(MethodNode mth, InsnArg iterableArg, RegisterArg iterVar) {
|
||||
ArgType iterableType = iterableArg.getType();
|
||||
ArgType varType = iterVar.getType();
|
||||
if (iterableType.isGeneric()) {
|
||||
@@ -283,10 +288,16 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
iterVar.setType(gType);
|
||||
return true;
|
||||
}
|
||||
if (ArgType.isInstanceOf(dex, gType, varType)) {
|
||||
if (ArgType.isInstanceOf(mth.dex(), gType, varType)) {
|
||||
return true;
|
||||
}
|
||||
LOG.warn("Generic type differs: {} and {}", gType, varType);
|
||||
ArgType wildcardType = gType.getWildcardType();
|
||||
if (wildcardType != null
|
||||
&& gType.getWildcardBounds() == 1
|
||||
&& ArgType.isInstanceOf(mth.dex(), wildcardType, varType)) {
|
||||
return true;
|
||||
}
|
||||
LOG.warn("Generic type differs: '{}' and '{}' in {}", gType, varType, mth);
|
||||
return false;
|
||||
}
|
||||
if (!iterableArg.isRegister()) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package jadx.tests.integration.generics;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.tests.api.utils.JadxMatchers.containsOne;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestGenerics6 extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
public void test1(Collection<? extends A> as) {
|
||||
for (A a : as) {
|
||||
a.f();
|
||||
}
|
||||
}
|
||||
|
||||
public void test2(Collection<? extends A> is) {
|
||||
for (I i : is) {
|
||||
i.f();
|
||||
}
|
||||
}
|
||||
|
||||
private interface I {
|
||||
void f();
|
||||
}
|
||||
|
||||
private class A implements I {
|
||||
public void f() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("for (A a : as) {"));
|
||||
// TODO: fix iterable arg type (unexpected cast to A in bytecode)
|
||||
// assertThat(code, containsOne("for (I i : is) {"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user