Commit 7bd17522 authored by Skylot's avatar Skylot

fix: add correct type propagation for check-cast and move instructions (#401)

parent ab7b6fc2
...@@ -252,6 +252,7 @@ public final class TypeUpdate { ...@@ -252,6 +252,7 @@ public final class TypeUpdate {
registry.put(InsnType.ARITH, this::suggestAllSameListener); registry.put(InsnType.ARITH, this::suggestAllSameListener);
registry.put(InsnType.NEG, this::suggestAllSameListener); registry.put(InsnType.NEG, this::suggestAllSameListener);
registry.put(InsnType.NOT, this::suggestAllSameListener); registry.put(InsnType.NOT, this::suggestAllSameListener);
registry.put(InsnType.CHECK_CAST, this::checkCastListener);
return registry; return registry;
} }
...@@ -263,20 +264,23 @@ public final class TypeUpdate { ...@@ -263,20 +264,23 @@ public final class TypeUpdate {
private TypeUpdateResult moveListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) { private TypeUpdateResult moveListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
boolean assignChanged = isAssign(insn, arg); boolean assignChanged = isAssign(insn, arg);
InsnArg changeArg = assignChanged ? insn.getArg(0) : insn.getResult(); InsnArg changeArg = assignChanged ? insn.getArg(0) : insn.getResult();
TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType); boolean allowReject;
if (result == REJECT && changeArg.getType().isTypeKnown()) { if (changeArg.getType().isTypeKnown()) {
// allow result to be wider // allow result to be wider
if (assignChanged) {
TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType()); TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType());
if (compareTypes.isWider() && inBounds(changeArg, candidateType)) { boolean correctType = assignChanged ? compareTypes.isWider() : compareTypes.isNarrow();
return CHANGED; if (correctType && inBounds(changeArg, candidateType)) {
} allowReject = true;
} else { } else {
TypeCompareEnum compareTypes = comparator.compareTypes(changeArg.getType(), candidateType); return REJECT;
if (compareTypes.isWider() && inBounds(changeArg, candidateType)) {
return CHANGED;
} }
} else {
allowReject = false;
} }
TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType);
if (result == REJECT && allowReject) {
return CHANGED;
} }
return result; return result;
} }
...@@ -324,6 +328,15 @@ public final class TypeUpdate { ...@@ -324,6 +328,15 @@ public final class TypeUpdate {
return allSame ? SAME : CHANGED; return allSame ? SAME : CHANGED;
} }
private TypeUpdateResult checkCastListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
if (!isAssign(insn, arg)) {
return SAME;
}
InsnArg insnArg = insn.getArg(0);
TypeUpdateResult result = updateTypeChecked(updateInfo, insnArg, candidateType);
return result == REJECT ? SAME : result;
}
private TypeUpdateResult arrayGetListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) { private TypeUpdateResult arrayGetListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
if (isAssign(insn, arg)) { if (isAssign(insn, arg)) {
return updateTypeChecked(updateInfo, insn.getArg(0), ArgType.array(candidateType)); return updateTypeChecked(updateInfo, insn.getArg(0), ArgType.array(candidateType));
......
package jadx.tests.integration.types;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestTypeResolver7 extends IntegrationTest {
public static class TestCls {
public void test(boolean a, boolean b) {
Object obj = null;
if (a) {
use(b ? (Exception) getObj() : (Exception) obj);
} else {
Runnable r = (Runnable) obj;
if (b) {
r = (Runnable) getObj();
}
use(r);
}
}
private Object getObj() {
return null;
}
private void use(Exception e) {}
private void use(Runnable r) {}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("use(b ? (Exception) getObj() : null);"));
}
@Test
public void testNoDebug() {
noDebugInfo();
getClassNode(TestCls.class);
}
}
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