fix: add correct type propagation for check-cast and move instructions (#401)
This commit is contained in:
@@ -252,6 +252,7 @@ public final class TypeUpdate {
|
||||
registry.put(InsnType.ARITH, this::suggestAllSameListener);
|
||||
registry.put(InsnType.NEG, this::suggestAllSameListener);
|
||||
registry.put(InsnType.NOT, this::suggestAllSameListener);
|
||||
registry.put(InsnType.CHECK_CAST, this::checkCastListener);
|
||||
return registry;
|
||||
}
|
||||
|
||||
@@ -263,20 +264,23 @@ public final class TypeUpdate {
|
||||
private TypeUpdateResult moveListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
|
||||
boolean assignChanged = isAssign(insn, arg);
|
||||
InsnArg changeArg = assignChanged ? insn.getArg(0) : insn.getResult();
|
||||
TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType);
|
||||
if (result == REJECT && changeArg.getType().isTypeKnown()) {
|
||||
boolean allowReject;
|
||||
if (changeArg.getType().isTypeKnown()) {
|
||||
// allow result to be wider
|
||||
if (assignChanged) {
|
||||
TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType());
|
||||
if (compareTypes.isWider() && inBounds(changeArg, candidateType)) {
|
||||
return CHANGED;
|
||||
}
|
||||
TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType());
|
||||
boolean correctType = assignChanged ? compareTypes.isWider() : compareTypes.isNarrow();
|
||||
if (correctType && inBounds(changeArg, candidateType)) {
|
||||
allowReject = true;
|
||||
} else {
|
||||
TypeCompareEnum compareTypes = comparator.compareTypes(changeArg.getType(), candidateType);
|
||||
if (compareTypes.isWider() && inBounds(changeArg, candidateType)) {
|
||||
return CHANGED;
|
||||
}
|
||||
return REJECT;
|
||||
}
|
||||
} else {
|
||||
allowReject = false;
|
||||
}
|
||||
|
||||
TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType);
|
||||
if (result == REJECT && allowReject) {
|
||||
return CHANGED;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -324,6 +328,15 @@ public final class TypeUpdate {
|
||||
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) {
|
||||
if (isAssign(insn, arg)) {
|
||||
return updateTypeChecked(updateInfo, insn.getArg(0), ArgType.array(candidateType));
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user