Commit 3782aa7d authored by Skylot's avatar Skylot

core: fix wildcard type in iterable loop

parent d5740c1b
......@@ -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;
}
ArgType wildcardType = gType.getWildcardType();
if (wildcardType != null
&& gType.getWildcardBounds() == 1
&& ArgType.isInstanceOf(mth.dex(), wildcardType, varType)) {
return true;
}
LOG.warn("Generic type differs: {} and {}", gType, varType);
LOG.warn("Generic type differs: '{}' and '{}' in {}", gType, varType, mth);
return false;
}
if (!iterableArg.isRegister()) {
......
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) {"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment