Skip to content

Commit

Permalink
core: fix wildcard type in iterable loop
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Apr 7, 2015
1 parent d5740c1 commit 3782aa7
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
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;
Expand Down Expand Up @@ -232,14 +231,23 @@ private static boolean checkIterableForEach(MethodNode mth, LoopRegion loopRegio
}
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);
Expand All @@ -255,9 +263,6 @@ private static boolean checkIterableForEach(MethodNode mth, LoopRegion loopRegio
} else {
toSkip.add(nextCall);
}
if (iterVar == null || !fixIterableType(mth.dex(), iterableArg, iterVar)) {
return false;
}

assignInsn.add(AFlag.SKIP);
for (InsnNode insnNode : toSkip) {
Expand All @@ -267,7 +272,7 @@ private static boolean checkIterableForEach(MethodNode mth, LoopRegion loopRegio
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()) {
Expand All @@ -283,10 +288,16 @@ private static boolean fixIterableType(DexNode dex, InsnArg iterableArg, Registe
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()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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) {"));
}
}

0 comments on commit 3782aa7

Please sign in to comment.