fix: resolve generic type vars for instance field get instruction (#918)
This commit is contained in:
@@ -61,6 +61,9 @@ public class TypeUtils {
|
||||
}
|
||||
|
||||
private void expandTypeVar(NotificationAttrNode node, ArgType type, Collection<ArgType> typeVars) {
|
||||
if (typeVars.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
boolean allExtendsEmpty = true;
|
||||
for (ArgType argType : typeVars) {
|
||||
if (notEmpty(argType.getExtendTypes())) {
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package jadx.core.dex.visitors.typeinference;
|
||||
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
|
||||
/**
|
||||
* Dynamic bound for instance field get of generic type.
|
||||
* Bound type calculated using instance generic type.
|
||||
*/
|
||||
public final class TypeBoundFieldGetAssign implements ITypeBoundDynamic {
|
||||
private final RootNode root;
|
||||
private final IndexInsnNode getNode;
|
||||
private final FieldInfo fieldInfo;
|
||||
private final ArgType initType;
|
||||
|
||||
public TypeBoundFieldGetAssign(RootNode root, IndexInsnNode getNode, ArgType initType) {
|
||||
this.root = root;
|
||||
this.getNode = getNode;
|
||||
this.fieldInfo = ((FieldInfo) getNode.getIndex());
|
||||
this.initType = initType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundEnum getBound() {
|
||||
return BoundEnum.ASSIGN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgType getType(TypeUpdateInfo updateInfo) {
|
||||
return getResultType(updateInfo.getType(getInstanceArg()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgType getType() {
|
||||
return getResultType(getInstanceArg().getType());
|
||||
}
|
||||
|
||||
private ArgType getResultType(ArgType instanceType) {
|
||||
ArgType resultGeneric = root.getTypeUtils().replaceClassGenerics(instanceType, initType);
|
||||
if (resultGeneric != null && !resultGeneric.isWildcard()) {
|
||||
return resultGeneric;
|
||||
}
|
||||
return initType; // TODO: check if this type is allowed in current scope
|
||||
}
|
||||
|
||||
private InsnArg getInstanceArg() {
|
||||
return getNode.getArg(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisterArg getArg() {
|
||||
return getNode.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TypeBoundFieldGetAssign that = (TypeBoundFieldGetAssign) o;
|
||||
return getNode.equals(that.getNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getNode.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FieldGetAssign{" + fieldInfo
|
||||
+ ", type=" + getType()
|
||||
+ ", instanceArg=" + getInstanceArg()
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
+12
@@ -293,6 +293,10 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
addBound(typeInfo, makeAssignInvokeBound((InvokeNode) insn));
|
||||
break;
|
||||
|
||||
case IGET:
|
||||
addBound(typeInfo, makeAssignFieldGetBound((IndexInsnNode) insn));
|
||||
break;
|
||||
|
||||
case CHECK_CAST:
|
||||
addBound(typeInfo, new TypeBoundCheckCastAssign(root, (IndexInsnNode) insn));
|
||||
break;
|
||||
@@ -304,6 +308,14 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private ITypeBound makeAssignFieldGetBound(IndexInsnNode insn) {
|
||||
ArgType initType = insn.getResult().getInitType();
|
||||
if (initType.containsTypeVariable()) {
|
||||
return new TypeBoundFieldGetAssign(root, insn, initType);
|
||||
}
|
||||
return new TypeBoundConst(BoundEnum.ASSIGN, initType);
|
||||
}
|
||||
|
||||
private ITypeBound makeAssignInvokeBound(InvokeNode invokeNode) {
|
||||
ArgType boundType = invokeNode.getCallMth().getReturnType();
|
||||
ArgType genericReturnType = root.getMethodUtils().getMethodGenericReturnType(invokeNode);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package jadx.tests.integration.generics;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestGenericFields extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
public static class Summary {
|
||||
Value<Amount> price;
|
||||
}
|
||||
|
||||
public static class Value<T> {
|
||||
T value;
|
||||
}
|
||||
|
||||
public static class Amount {
|
||||
String cur;
|
||||
int val;
|
||||
}
|
||||
|
||||
public String test(Summary summary) {
|
||||
Amount amount = summary.price.value;
|
||||
return amount.val + " " + amount.cur;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.doesNotContain("T t = ")
|
||||
.containsOne("Amount amount =");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user