fix: add cast to exact type on field access (#729)
This commit is contained in:
@@ -41,10 +41,15 @@ public class IndexInsnNode extends InsnNode {
|
||||
switch (insnType) {
|
||||
case CAST:
|
||||
case CHECK_CAST:
|
||||
return InsnUtils.formatOffset(offset) + ": "
|
||||
+ InsnUtils.insnTypeToString(insnType)
|
||||
+ getResult() + " = (" + InsnUtils.indexToString(index) + ") "
|
||||
+ Utils.listToString(getArguments());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(InsnUtils.formatOffset(offset)).append(": ");
|
||||
sb.append(insnType).append(' ');
|
||||
if (getResult() != null) {
|
||||
sb.append(getResult()).append(" = ");
|
||||
}
|
||||
sb.append('(').append(InsnUtils.indexToString(index)).append(") ");
|
||||
sb.append(Utils.listToString(getArguments()));
|
||||
return sb.toString();
|
||||
|
||||
default:
|
||||
return super.toString() + ' ' + InsnUtils.indexToString(index);
|
||||
|
||||
@@ -30,6 +30,7 @@ import jadx.core.dex.nodes.utils.MethodUtils;
|
||||
import jadx.core.dex.nodes.utils.TypeUtils;
|
||||
import jadx.core.dex.visitors.DepthTraversal;
|
||||
import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
import jadx.core.dex.visitors.typeinference.TypeCompare;
|
||||
import jadx.core.dex.visitors.typeinference.TypeUpdate;
|
||||
import jadx.core.utils.CacheStorage;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
@@ -424,6 +425,10 @@ public class RootNode {
|
||||
return typeUpdate;
|
||||
}
|
||||
|
||||
public TypeCompare getTypeCompare() {
|
||||
return typeUpdate.getTypeCompare();
|
||||
}
|
||||
|
||||
public ICodeCache getCodeCache() {
|
||||
return codeCache;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import jadx.core.dex.instructions.NewArrayNode;
|
||||
import jadx.core.dex.instructions.SwitchInsn;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.instructions.args.NamedArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
@@ -49,6 +50,7 @@ import jadx.core.dex.trycatch.ExcHandlerAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.visitors.regions.variables.ProcessVariables;
|
||||
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
|
||||
import jadx.core.dex.visitors.typeinference.TypeCompareEnum;
|
||||
import jadx.core.utils.InsnRemover;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
@@ -144,6 +146,11 @@ public class ModVisitor extends AbstractVisitor {
|
||||
fixPrimitiveCast(mth, block, i, insn);
|
||||
break;
|
||||
|
||||
case IPUT:
|
||||
case IGET:
|
||||
fixTypeForFieldAccess(mth, (IndexInsnNode) insn);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -152,6 +159,31 @@ public class ModVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void fixTypeForFieldAccess(MethodNode mth, IndexInsnNode insn) {
|
||||
InsnArg instanceArg = insn.getArg(insn.getType() == InsnType.IGET ? 0 : 1);
|
||||
if (instanceArg.contains(AFlag.SUPER)) {
|
||||
return;
|
||||
}
|
||||
if (instanceArg.isInsnWrap() && ((InsnWrapArg) instanceArg).getWrapInsn().getType() == InsnType.CAST) {
|
||||
return;
|
||||
}
|
||||
FieldInfo fieldInfo = (FieldInfo) insn.getIndex();
|
||||
ArgType clsType = fieldInfo.getDeclClass().getType();
|
||||
ArgType instanceType = instanceArg.getType();
|
||||
TypeCompareEnum result = mth.root().getTypeCompare().compareTypes(instanceType, clsType);
|
||||
if (result.isEqual() || (result == TypeCompareEnum.NARROW_BY_GENERIC && !instanceType.isGenericType())) {
|
||||
return;
|
||||
}
|
||||
IndexInsnNode castInsn = new IndexInsnNode(InsnType.CAST, clsType, 1);
|
||||
castInsn.addArg(instanceArg.duplicate());
|
||||
castInsn.add(AFlag.EXPLICIT_CAST);
|
||||
|
||||
InsnArg castArg = InsnArg.wrapInsnIntoArg(castInsn);
|
||||
castArg.setType(clsType);
|
||||
insn.replaceArg(instanceArg, castArg);
|
||||
InsnRemover.unbindArgUsage(mth, instanceArg);
|
||||
}
|
||||
|
||||
private static void replaceConstKeys(ClassNode parentClass, SwitchInsn insn) {
|
||||
int[] keys = insn.getKeys();
|
||||
int len = keys.length;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package jadx.tests.integration.types;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestFieldAccess extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
private String field;
|
||||
|
||||
static <T extends TestCls> T testPut(T t) {
|
||||
((TestCls) t).field = "";
|
||||
return t;
|
||||
}
|
||||
|
||||
static <T extends TestCls> T testGet(T t) {
|
||||
System.out.println(((TestCls) t).field);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.doesNotContain("t.field");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user