diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java index c005f9e0c6e..6d8a10d7d68 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java @@ -270,7 +270,6 @@ public String getDetailedVarInfo(MethodNode mth) { if (!types.isEmpty()) { sb.append(", types: ").append(types); } - sb.append(", assign insn: ").append(getAssign().getParentInsn()); return sb.toString(); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java index 729642eaf6c..0d51c31daa2 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java @@ -92,7 +92,13 @@ private boolean resolveTypes(MethodNode mth) { if (tryInsertAdditionalMove(mth)) { return true; } - return runMultiVariableSearch(mth); + if (runMultiVariableSearch(mth)) { + return true; + } + if (tryRemoveGenerics(mth)) { + return true; + } + return false; } /** @@ -124,11 +130,15 @@ private boolean runTypePropagation(MethodNode mth) { private boolean runMultiVariableSearch(MethodNode mth) { TypeSearch typeSearch = new TypeSearch(mth); try { - boolean success = typeSearch.run(); - if (!success) { + if (!typeSearch.run()) { mth.addWarn("Multi-variable type inference failed"); } - return success; + for (SSAVar var : mth.getSVars()) { + if (!var.getTypeInfo().getType().isTypeKnown()) { + return false; + } + } + return true; } catch (Exception e) { mth.addWarn("Multi-variable type inference failed. Error: " + Utils.getStackTrace(e)); return false; @@ -366,6 +376,48 @@ private boolean tryDeduceType(MethodNode mth, SSAVar var, @Nullable ArgType type return false; } + private boolean tryRemoveGenerics(MethodNode mth) { + boolean resolved = true; + for (SSAVar var : mth.getSVars()) { + ArgType type = var.getTypeInfo().getType(); + if (!type.isTypeKnown() && !var.isTypeImmutable() + && !tryRawType(mth, var)) { + resolved = false; + } + } + return resolved; + } + + private boolean tryRawType(MethodNode mth, SSAVar var) { + Set objTypes = new LinkedHashSet<>(); + for (ITypeBound bound : var.getTypeInfo().getBounds()) { + ArgType boundType = bound.getType(); + if (boundType.isTypeKnown() && boundType.isObject()) { + objTypes.add(boundType); + } + } + if (objTypes.isEmpty()) { + return false; + } + for (ArgType objType : objTypes) { + if (checkRawType(mth, var, objType)) { + mth.addDebugComment("Type inference failed for " + var.toShortString() + "." + + " Raw type applied. Possible types: " + Utils.listToString(objTypes)); + return true; + } + } + return false; + } + + private boolean checkRawType(MethodNode mth, SSAVar var, ArgType objType) { + if (objType.isObject() && objType.containsGeneric()) { + ArgType rawType = ArgType.object(objType.getObject()); + TypeUpdateResult result = typeUpdate.applyWithWiderAllow(var, rawType); + return result == TypeUpdateResult.CHANGED; + } + return false; + } + private boolean trySplitConstInsns(MethodNode mth) { boolean constSplitted = false; for (SSAVar var : new ArrayList<>(mth.getSVars())) {