Commit ffc64204 authored by Skylot's avatar Skylot

core: fix type check for loop over iterable.

parent 8de6190a
......@@ -224,7 +224,8 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
InsnArg iterableArg = assignInsn.getArg(0);
InsnNode hasNextCall = useList.get(0).getParentInsn();
InsnNode nextCall = useList.get(1).getParentInsn();
if (!checkInvoke(hasNextCall, "java.util.Iterator", "hasNext()Z", 0)
if (hasNextCall == null || nextCall == null
|| !checkInvoke(hasNextCall, "java.util.Iterator", "hasNext()Z", 0)
|| !checkInvoke(nextCall, "java.util.Iterator", "next()Ljava/lang/Object;", 0)) {
return false;
}
......@@ -239,7 +240,7 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
} else {
iterVar = parentInsn.getResult();
InsnArg castArg = BlockUtils.searchWrappedInsnParent(mth, parentInsn);
if (castArg != null) {
if (castArg != null && castArg.getParentInsn() != null) {
castArg.getParentInsn().replaceArg(castArg, iterVar);
} else {
// cast not inlined
......@@ -266,28 +267,35 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
}
private static boolean fixIterableType(InsnArg iterableArg, RegisterArg iterVar) {
ArgType type = iterableArg.getType();
if (type.isGeneric()) {
ArgType[] genericTypes = type.getGenericTypes();
if (genericTypes != null && genericTypes.length == 1) {
ArgType iterableType = iterableArg.getType();
ArgType varType = iterVar.getType();
if (iterableType.isGeneric()) {
ArgType[] genericTypes = iterableType.getGenericTypes();
if (genericTypes == null || genericTypes.length != 1) {
return false;
}
ArgType gType = genericTypes[0];
if (ArgType.isInstanceOf(gType, iterVar.getType())) {
if (gType.equals(varType)) {
return true;
} else {
LOG.warn("Generic type differs: {} and {}", type, iterVar.getType());
}
if (gType.isGenericType()) {
iterVar.setType(gType);
return true;
}
if (ArgType.isInstanceOf(gType, varType)) {
return true;
}
LOG.warn("Generic type differs: {} and {}", gType, varType);
return false;
}
} else {
if (!iterableArg.isRegister()) {
return true;
}
// TODO: add checks
type = ArgType.generic(type.getObject(), new ArgType[]{iterVar.getType()});
iterableArg.setType(type);
iterableType = ArgType.generic(iterableType.getObject(), new ArgType[]{varType});
iterableArg.setType(iterableType);
return true;
}
return false;
}
/**
* Check if instruction is a interface invoke with corresponding parameters.
......
package jadx.tests.integration.loops;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import java.util.Set;
import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestIterableForEach3 extends IntegrationTest {
public static class TestCls<T extends String> {
private Set<T> a;
private Set<T> b;
private void test(T str) {
Set<T> set = str.length() == 1 ? a : b;
for (T s : set) {
if (s.length() == str.length()) {
if (str.length() == 0) {
set.remove(s);
} else {
set.add(str);
}
return;
}
}
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("for (T s : set) {"));
assertThat(code, containsOne("if (str.length() == 0) {"));
// TODO move return outside 'if'
}
}
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