提交 7396c759 编写于 作者: S Skylot

fix: resolve type variables in invoke from arg types

上级 d39849ad
......@@ -154,6 +154,30 @@ public class TypeUtils {
return replaceMap;
}
public Map<ArgType, ArgType> getTypeVarMappingForInvoke(BaseInvokeNode invokeInsn) {
IMethodDetails mthDetails = root.getMethodUtils().getMethodDetails(invokeInsn);
if (mthDetails == null) {
return Collections.emptyMap();
}
Map<ArgType, ArgType> map = new HashMap<>(1 + invokeInsn.getArgsCount());
addTypeVarMapping(map, mthDetails.getReturnType(), invokeInsn.getResult());
int argCount = Math.min(mthDetails.getArgTypes().size(), invokeInsn.getArgsCount());
for (int i = 0; i < argCount; i++) {
addTypeVarMapping(map, mthDetails.getArgTypes().get(i), invokeInsn.getArg(i));
}
return map;
}
private static void addTypeVarMapping(Map<ArgType, ArgType> map, ArgType typeVar, InsnArg arg) {
if (arg == null || typeVar == null || !typeVar.isTypeKnown()) {
return;
}
if (typeVar.isGenericType()) {
map.put(typeVar, arg.getType());
}
// TODO: resolve inner type vars: 'List<T> -> List<String>' to 'T -> String'
}
@Nullable
public ArgType replaceMethodGenerics(BaseInvokeNode invokeInsn, IMethodDetails details, ArgType typeWithGeneric) {
if (typeWithGeneric == null) {
......
......@@ -22,6 +22,7 @@ import jadx.core.dex.nodes.IMethodDetails;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.nodes.utils.TypeUtils;
import jadx.core.dex.visitors.methods.MutableMethodDetails;
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.dex.visitors.typeinference.TypeCompare;
......@@ -156,9 +157,14 @@ public class MethodInvokeVisitor extends AbstractVisitor {
}
private Map<ArgType, ArgType> getTypeVarsMapping(BaseInvokeNode invokeInsn) {
ArgType declClsType = invokeInsn.getCallMth().getDeclClass().getType();
MethodInfo callMthInfo = invokeInsn.getCallMth();
ArgType declClsType = callMthInfo.getDeclClass().getType();
ArgType callClsType = getClsCallType(invokeInsn, declClsType);
return root.getTypeUtils().getTypeVariablesMapping(callClsType);
TypeUtils typeUtils = root.getTypeUtils();
Map<ArgType, ArgType> clsTypeVars = typeUtils.getTypeVariablesMapping(callClsType);
Map<ArgType, ArgType> mthTypeVars = typeUtils.getTypeVarMappingForInvoke(invokeInsn);
return Utils.mergeMaps(clsTypeVars, mthTypeVars);
}
private ArgType getClsCallType(BaseInvokeNode invokeInsn, ArgType declClsType) {
......
......@@ -246,6 +246,22 @@ public class Utils {
return Collections.unmodifiableMap(result);
}
/**
* Merge two maps. Return HashMap as result. Second map will override values from first map.
*/
public static <K, V> Map<K, V> mergeMaps(Map<K, V> first, Map<K, V> second) {
if (isEmpty(first)) {
return second;
}
if (isEmpty(second)) {
return first;
}
Map<K, V> result = new HashMap<>(first.size() + second.size());
result.putAll(first);
result.putAll(second);
return result;
}
@Nullable
public static <T> T getOne(@Nullable List<T> list) {
if (list == null || list.size() != 1) {
......@@ -277,6 +293,10 @@ public class Utils {
return col != null && !col.isEmpty();
}
public static <K, V> boolean isEmpty(Map<K, V> map) {
return map == null || map.isEmpty();
}
public static <T> boolean isEmpty(T[] arr) {
return arr == null || arr.length == 0;
}
......
package jadx.tests.integration.enums;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestEnums9 extends IntegrationTest {
public static class TestCls {
public enum Types {
INT,
FLOAT,
LONG,
DOUBLE,
OBJECT,
ARRAY;
private static Set<Types> primitives = EnumSet.of(INT, FLOAT, LONG, DOUBLE);
public static List<Types> references = new ArrayList<>();
static {
references.add(OBJECT);
references.add(ARRAY);
}
public static Set<Types> getPrimitives() {
return primitives;
}
}
public void check() {
assertThat(Types.getPrimitives()).contains(Types.INT);
assertThat(Types.references).hasSize(2);
}
}
@Test
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("EnumSet.of((Enum) INT,");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册