Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
keyescgm
jadx
提交
0541748e
J
jadx
项目概览
keyescgm
/
jadx
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jadx
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0541748e
编写于
6月 03, 2021
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: resolve type variables from super types (#870)
上级
cf1d9e83
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
323 addition
and
34 deletion
+323
-34
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
+1
-1
jadx-core/src/main/java/jadx/core/clsp/ClspMethod.java
jadx-core/src/main/java/jadx/core/clsp/ClspMethod.java
+5
-0
jadx-core/src/main/java/jadx/core/clsp/SimpleMethodDetails.java
...ore/src/main/java/jadx/core/clsp/SimpleMethodDetails.java
+5
-0
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
+2
-0
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/ClassTypeVarsAttr.java
...ava/jadx/core/dex/attributes/nodes/ClassTypeVarsAttr.java
+47
-0
jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java
...rc/main/java/jadx/core/dex/instructions/args/ArgType.java
+2
-0
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+24
-3
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
+16
-2
jadx-core/src/main/java/jadx/core/dex/nodes/utils/TypeUtils.java
...re/src/main/java/jadx/core/dex/nodes/utils/TypeUtils.java
+96
-5
jadx-core/src/main/java/jadx/core/dex/visitors/methods/MutableMethodDetails.java
.../jadx/core/dex/visitors/methods/MutableMethodDetails.java
+5
-0
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeBoundInvokeAssign.java
...ore/dex/visitors/typeinference/TypeBoundInvokeAssign.java
+18
-4
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
...core/dex/visitors/typeinference/TypeInferenceVisitor.java
+6
-3
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java
...java/jadx/core/dex/visitors/typeinference/TypeUpdate.java
+10
-0
jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics2.java
...t/java/jadx/tests/integration/generics/TestGenerics2.java
+12
-16
jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics8.java
...t/java/jadx/tests/integration/generics/TestGenerics8.java
+29
-0
jadx-core/src/test/java/jadx/tests/integration/generics/TestTypeVarsFromSuperClass.java
...ests/integration/generics/TestTypeVarsFromSuperClass.java
+45
-0
未找到文件。
jadx-core/src/main/java/jadx/core/clsp/ClspGraph.java
浏览文件 @
0541748e
...
@@ -177,7 +177,7 @@ public class ClspGraph {
...
@@ -177,7 +177,7 @@ public class ClspGraph {
private
Set
<
String
>
putInSuperTypesCache
(
String
clsName
,
Set
<
String
>
result
)
{
private
Set
<
String
>
putInSuperTypesCache
(
String
clsName
,
Set
<
String
>
result
)
{
if
(
result
.
isEmpty
())
{
if
(
result
.
isEmpty
())
{
Set
<
String
>
empty
=
Collections
.
emptySet
();
Set
<
String
>
empty
=
Collections
.
emptySet
();
superTypesCache
.
put
(
clsName
,
result
);
superTypesCache
.
put
(
clsName
,
empty
);
return
empty
;
return
empty
;
}
}
superTypesCache
.
put
(
clsName
,
result
);
superTypesCache
.
put
(
clsName
,
result
);
...
...
jadx-core/src/main/java/jadx/core/clsp/ClspMethod.java
浏览文件 @
0541748e
...
@@ -99,6 +99,11 @@ public class ClspMethod implements IMethodDetails, Comparable<ClspMethod> {
...
@@ -99,6 +99,11 @@ public class ClspMethod implements IMethodDetails, Comparable<ClspMethod> {
return
this
.
methodInfo
.
compareTo
(
other
.
methodInfo
);
return
this
.
methodInfo
.
compareTo
(
other
.
methodInfo
);
}
}
@Override
public
String
toAttrString
()
{
return
IMethodDetails
.
super
.
toAttrString
()
+
" (c)"
;
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
();
StringBuilder
sb
=
new
StringBuilder
();
...
...
jadx-core/src/main/java/jadx/core/clsp/SimpleMethodDetails.java
浏览文件 @
0541748e
...
@@ -55,6 +55,11 @@ public class SimpleMethodDetails implements IMethodDetails {
...
@@ -55,6 +55,11 @@ public class SimpleMethodDetails implements IMethodDetails {
return
AccessFlags
.
PUBLIC
;
return
AccessFlags
.
PUBLIC
;
}
}
@Override
public
String
toAttrString
()
{
return
IMethodDetails
.
super
.
toAttrString
()
+
" (s)"
;
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"SimpleMethodDetails{"
+
methodInfo
+
'}'
;
return
"SimpleMethodDetails{"
+
methodInfo
+
'}'
;
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
浏览文件 @
0541748e
...
@@ -7,6 +7,7 @@ import java.util.Set;
...
@@ -7,6 +7,7 @@ import java.util.Set;
import
jadx.core.dex.attributes.annotations.AnnotationsList
;
import
jadx.core.dex.attributes.annotations.AnnotationsList
;
import
jadx.core.dex.attributes.annotations.MethodParameters
;
import
jadx.core.dex.attributes.annotations.MethodParameters
;
import
jadx.core.dex.attributes.fldinit.FieldInitAttr
;
import
jadx.core.dex.attributes.fldinit.FieldInitAttr
;
import
jadx.core.dex.attributes.nodes.ClassTypeVarsAttr
;
import
jadx.core.dex.attributes.nodes.DeclareVariablesAttr
;
import
jadx.core.dex.attributes.nodes.DeclareVariablesAttr
;
import
jadx.core.dex.attributes.nodes.EdgeInsnAttr
;
import
jadx.core.dex.attributes.nodes.EdgeInsnAttr
;
import
jadx.core.dex.attributes.nodes.EnumClassAttr
;
import
jadx.core.dex.attributes.nodes.EnumClassAttr
;
...
@@ -58,6 +59,7 @@ public class AType<T extends IAttribute> {
...
@@ -58,6 +59,7 @@ public class AType<T extends IAttribute> {
public
static
final
AType
<
SourceFileAttr
>
SOURCE_FILE
=
new
AType
<>();
public
static
final
AType
<
SourceFileAttr
>
SOURCE_FILE
=
new
AType
<>();
public
static
final
AType
<
EnumClassAttr
>
ENUM_CLASS
=
new
AType
<>();
public
static
final
AType
<
EnumClassAttr
>
ENUM_CLASS
=
new
AType
<>();
public
static
final
AType
<
EnumMapAttr
>
ENUM_MAP
=
new
AType
<>();
public
static
final
AType
<
EnumMapAttr
>
ENUM_MAP
=
new
AType
<>();
public
static
final
AType
<
ClassTypeVarsAttr
>
CLASS_TYPE_VARS
=
new
AType
<>();
// field
// field
public
static
final
AType
<
FieldInitAttr
>
FIELD_INIT
=
new
AType
<>();
public
static
final
AType
<
FieldInitAttr
>
FIELD_INIT
=
new
AType
<>();
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/ClassTypeVarsAttr.java
0 → 100644
浏览文件 @
0541748e
package
jadx.core.dex.attributes.nodes
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.IAttribute
;
import
jadx.core.dex.instructions.args.ArgType
;
public
class
ClassTypeVarsAttr
implements
IAttribute
{
public
static
final
ClassTypeVarsAttr
EMPTY
=
new
ClassTypeVarsAttr
(
Collections
.
emptyList
(),
Collections
.
emptyMap
());
/**
* Type vars defined in current class
*/
private
final
List
<
ArgType
>
typeVars
;
/**
* Type vars mapping in current and super types:
* TypeRawObj -> (TypeVarInSuperType -> TypeVarFromThisClass)
*/
private
final
Map
<
String
,
Map
<
ArgType
,
ArgType
>>
superTypeMaps
;
public
ClassTypeVarsAttr
(
List
<
ArgType
>
typeVars
,
Map
<
String
,
Map
<
ArgType
,
ArgType
>>
superTypeMaps
)
{
this
.
typeVars
=
typeVars
;
this
.
superTypeMaps
=
superTypeMaps
;
}
public
List
<
ArgType
>
getTypeVars
()
{
return
typeVars
;
}
public
Map
<
String
,
Map
<
ArgType
,
ArgType
>>
getSuperTypeMaps
()
{
return
superTypeMaps
;
}
@Override
public
AType
<
ClassTypeVarsAttr
>
getType
()
{
return
AType
.
CLASS_TYPE_VARS
;
}
@Override
public
String
toString
()
{
return
"ClassTypeVarsAttr{"
+
typeVars
+
", super maps: "
+
superTypeMaps
+
'}'
;
}
}
jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java
浏览文件 @
0541748e
...
@@ -7,6 +7,7 @@ import java.util.Objects;
...
@@ -7,6 +7,7 @@ import java.util.Objects;
import
java.util.function.Function
;
import
java.util.function.Function
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
org.jetbrains.annotations.TestOnly
;
import
org.jetbrains.annotations.TestOnly
;
import
jadx.core.Consts
;
import
jadx.core.Consts
;
...
@@ -823,6 +824,7 @@ public abstract class ArgType {
...
@@ -823,6 +824,7 @@ public abstract class ArgType {
* Recursively visit all subtypes of this type.
* Recursively visit all subtypes of this type.
* To exit return non-null value.
* To exit return non-null value.
*/
*/
@Nullable
public
<
R
>
R
visitTypes
(
Function
<
ArgType
,
R
>
visitor
)
{
public
<
R
>
R
visitTypes
(
Function
<
ArgType
,
R
>
visitor
)
{
R
r
=
visitor
.
apply
(
this
);
R
r
=
visitor
.
apply
(
this
);
if
(
r
!=
null
)
{
if
(
r
!=
null
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
浏览文件 @
0541748e
...
@@ -7,6 +7,7 @@ import java.util.LinkedHashSet;
...
@@ -7,6 +7,7 @@ import java.util.LinkedHashSet;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.function.BiConsumer
;
import
java.util.function.Consumer
;
import
java.util.function.Consumer
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
...
@@ -35,6 +36,7 @@ import jadx.core.dex.info.FieldInfo;
...
@@ -35,6 +36,7 @@ import jadx.core.dex.info.FieldInfo;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.nodes.utils.TypeUtils
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
...
@@ -68,11 +70,17 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
...
@@ -68,11 +70,17 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
private
volatile
ProcessState
state
=
ProcessState
.
NOT_LOADED
;
private
volatile
ProcessState
state
=
ProcessState
.
NOT_LOADED
;
private
LoadStage
loadStage
=
LoadStage
.
NONE
;
private
LoadStage
loadStage
=
LoadStage
.
NONE
;
/** Top level classes used in this class (only for top level classes, empty for inners) */
/**
* Top level classes used in this class (only for top level classes, empty for inners)
*/
private
List
<
ClassNode
>
dependencies
=
Collections
.
emptyList
();
private
List
<
ClassNode
>
dependencies
=
Collections
.
emptyList
();
/** Classes which uses this class */
/**
* Classes which uses this class
*/
private
List
<
ClassNode
>
useIn
=
Collections
.
emptyList
();
private
List
<
ClassNode
>
useIn
=
Collections
.
emptyList
();
/** Methods which uses this class (by instructions only, definition is excluded) */
/**
* Methods which uses this class (by instructions only, definition is excluded)
*/
private
List
<
MethodNode
>
useInMth
=
Collections
.
emptyList
();
private
List
<
MethodNode
>
useInMth
=
Collections
.
emptyList
();
// cache maps
// cache maps
...
@@ -429,6 +437,19 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
...
@@ -429,6 +437,19 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
}
}
}
}
public
void
visitSuperTypes
(
BiConsumer
<
ArgType
,
ArgType
>
consumer
)
{
TypeUtils
typeUtils
=
root
.
getTypeUtils
();
ArgType
thisType
=
this
.
getType
();
if
(!
superClass
.
equals
(
ArgType
.
OBJECT
))
{
consumer
.
accept
(
thisType
,
superClass
);
typeUtils
.
visitSuperTypes
(
superClass
,
consumer
);
}
for
(
ArgType
iface
:
interfaces
)
{
consumer
.
accept
(
thisType
,
iface
);
typeUtils
.
visitSuperTypes
(
iface
,
consumer
);
}
}
public
boolean
hasNotGeneratedParent
()
{
public
boolean
hasNotGeneratedParent
()
{
if
(
contains
(
AFlag
.
DONT_GENERATE
))
{
if
(
contains
(
AFlag
.
DONT_GENERATE
))
{
return
true
;
return
true
;
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
浏览文件 @
0541748e
package
jadx.core.dex.nodes
;
package
jadx.core.dex.nodes
;
import
java.util.*
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Objects
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
org.jetbrains.annotations.Nullable
;
...
@@ -24,7 +27,13 @@ import jadx.core.dex.info.AccessInfo.AFType;
...
@@ -24,7 +27,13 @@ import jadx.core.dex.info.AccessInfo.AFType;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.InsnDecoder
;
import
jadx.core.dex.instructions.InsnDecoder
;
import
jadx.core.dex.instructions.args.*
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.CodeVar
;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.NamedArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.args.SSAVar
;
import
jadx.core.dex.instructions.args.VisibleVar
;
import
jadx.core.dex.nodes.VariableNode.VarKind
;
import
jadx.core.dex.nodes.VariableNode.VarKind
;
import
jadx.core.dex.nodes.utils.TypeUtils
;
import
jadx.core.dex.nodes.utils.TypeUtils
;
import
jadx.core.dex.regions.Region
;
import
jadx.core.dex.regions.Region
;
...
@@ -680,6 +689,11 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
...
@@ -680,6 +689,11 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
return
mthInfo
.
compareTo
(
o
.
mthInfo
);
return
mthInfo
.
compareTo
(
o
.
mthInfo
);
}
}
@Override
public
String
toAttrString
()
{
return
IMethodDetails
.
super
.
toAttrString
()
+
" (m)"
;
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
parentClass
+
"."
+
mthInfo
.
getName
()
return
parentClass
+
"."
+
mthInfo
.
getName
()
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/utils/TypeUtils.java
浏览文件 @
0541748e
...
@@ -7,11 +7,13 @@ import java.util.HashSet;
...
@@ -7,11 +7,13 @@ import java.util.HashSet;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.function.BiConsumer
;
import
org.jetbrains.annotations.Nullable
;
import
org.jetbrains.annotations.Nullable
;
import
jadx.core.clsp.ClspClass
;
import
jadx.core.clsp.ClspClass
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.ClassTypeVarsAttr
;
import
jadx.core.dex.attributes.nodes.MethodTypeVarsAttr
;
import
jadx.core.dex.attributes.nodes.MethodTypeVarsAttr
;
import
jadx.core.dex.attributes.nodes.NotificationAttrNode
;
import
jadx.core.dex.attributes.nodes.NotificationAttrNode
;
import
jadx.core.dex.instructions.BaseInvokeNode
;
import
jadx.core.dex.instructions.BaseInvokeNode
;
...
@@ -46,6 +48,19 @@ public class TypeUtils {
...
@@ -46,6 +48,19 @@ public class TypeUtils {
return
generics
==
null
?
Collections
.
emptyList
()
:
generics
;
return
generics
==
null
?
Collections
.
emptyList
()
:
generics
;
}
}
@Nullable
public
ClassTypeVarsAttr
getClassTypeVars
(
ArgType
type
)
{
ClassNode
classNode
=
root
.
resolveClass
(
type
);
if
(
classNode
==
null
)
{
return
null
;
}
ClassTypeVarsAttr
typeVarsAttr
=
classNode
.
get
(
AType
.
CLASS_TYPE_VARS
);
if
(
typeVarsAttr
!=
null
)
{
return
typeVarsAttr
;
}
return
buildClassTypeVarsAttr
(
classNode
);
}
public
ArgType
expandTypeVariables
(
ClassNode
cls
,
ArgType
type
)
{
public
ArgType
expandTypeVariables
(
ClassNode
cls
,
ArgType
type
)
{
if
(
type
.
containsTypeVariable
())
{
if
(
type
.
containsTypeVariable
())
{
expandTypeVar
(
cls
,
type
,
cls
.
getGenericTypeParameters
());
expandTypeVar
(
cls
,
type
,
cls
.
getGenericTypeParameters
());
...
@@ -109,6 +124,26 @@ public class TypeUtils {
...
@@ -109,6 +124,26 @@ public class TypeUtils {
return
typeVars
.
isEmpty
()
?
Collections
.
emptySet
()
:
typeVars
;
return
typeVars
.
isEmpty
()
?
Collections
.
emptySet
()
:
typeVars
;
}
}
/**
* Search for unknown type vars at current method. Return only first.
*
* @return unknown type var, null if not found
*/
@Nullable
public
ArgType
checkForUnknownTypeVars
(
MethodNode
mth
,
ArgType
checkType
)
{
Set
<
ArgType
>
knownTypeVars
=
getKnownTypeVarsAtMethod
(
mth
);
return
checkType
.
visitTypes
(
type
->
{
if
(
type
.
isGenericType
()
&&
!
knownTypeVars
.
contains
(
type
))
{
return
type
;
}
return
null
;
});
}
public
boolean
containsUnknownTypeVar
(
MethodNode
mth
,
ArgType
type
)
{
return
checkForUnknownTypeVars
(
mth
,
type
)
!=
null
;
}
/**
/**
* Replace generic types in {@code typeWithGeneric} using instance types
* Replace generic types in {@code typeWithGeneric} using instance types
* <br>
* <br>
...
@@ -121,21 +156,31 @@ public class TypeUtils {
...
@@ -121,21 +156,31 @@ public class TypeUtils {
*/
*/
@Nullable
@Nullable
public
ArgType
replaceClassGenerics
(
ArgType
instanceType
,
ArgType
typeWithGeneric
)
{
public
ArgType
replaceClassGenerics
(
ArgType
instanceType
,
ArgType
typeWithGeneric
)
{
if
(
typeWithGeneric
==
null
)
{
return
replaceClassGenerics
(
instanceType
,
instanceType
,
typeWithGeneric
);
}
@Nullable
public
ArgType
replaceClassGenerics
(
ArgType
instanceType
,
ArgType
genericSourceType
,
ArgType
typeWithGeneric
)
{
if
(
typeWithGeneric
==
null
||
genericSourceType
==
null
)
{
return
null
;
return
null
;
}
}
Map
<
ArgType
,
ArgType
>
replaceMap
=
getTypeVariablesMapping
(
instanceType
);
Map
<
ArgType
,
ArgType
>
typeVarsMap
;
if
(
replaceMap
.
isEmpty
())
{
ClassTypeVarsAttr
typeVars
=
getClassTypeVars
(
instanceType
);
if
(
typeVars
!=
null
)
{
typeVarsMap
=
typeVars
.
getSuperTypeMaps
().
get
(
genericSourceType
.
getObject
());
}
else
{
typeVarsMap
=
getTypeVariablesMapping
(
instanceType
);
}
if
(
typeVarsMap
==
null
)
{
return
null
;
return
null
;
}
}
return
replaceTypeVariablesUsingMap
(
typeWithGeneric
,
replace
Map
);
return
replaceTypeVariablesUsingMap
(
typeWithGeneric
,
typeVars
Map
);
}
}
public
Map
<
ArgType
,
ArgType
>
getTypeVariablesMapping
(
ArgType
clsType
)
{
public
Map
<
ArgType
,
ArgType
>
getTypeVariablesMapping
(
ArgType
clsType
)
{
if
(!
clsType
.
isGeneric
())
{
if
(!
clsType
.
isGeneric
())
{
return
Collections
.
emptyMap
();
return
Collections
.
emptyMap
();
}
}
List
<
ArgType
>
typeParameters
=
root
.
getTypeUtils
().
getClassGenerics
(
clsType
);
List
<
ArgType
>
typeParameters
=
root
.
getTypeUtils
().
getClassGenerics
(
clsType
);
if
(
typeParameters
.
isEmpty
())
{
if
(
typeParameters
.
isEmpty
())
{
return
Collections
.
emptyMap
();
return
Collections
.
emptyMap
();
...
@@ -239,4 +284,50 @@ public class TypeUtils {
...
@@ -239,4 +284,50 @@ public class TypeUtils {
}
}
return
null
;
return
null
;
}
}
private
ClassTypeVarsAttr
buildClassTypeVarsAttr
(
ClassNode
cls
)
{
Map
<
String
,
Map
<
ArgType
,
ArgType
>>
map
=
new
HashMap
<>();
ArgType
currentClsType
=
cls
.
getClassInfo
().
getType
();
map
.
put
(
currentClsType
.
getObject
(),
getTypeVariablesMapping
(
currentClsType
));
cls
.
visitSuperTypes
((
parent
,
type
)
->
{
List
<
ArgType
>
currentVars
=
type
.
getGenericTypes
();
if
(
Utils
.
isEmpty
(
currentVars
))
{
return
;
}
int
varsCount
=
currentVars
.
size
();
List
<
ArgType
>
sourceTypeVars
=
getClassGenerics
(
type
);
if
(
varsCount
==
sourceTypeVars
.
size
())
{
Map
<
ArgType
,
ArgType
>
parentTypeMap
=
map
.
get
(
parent
.
getObject
());
Map
<
ArgType
,
ArgType
>
varsMap
=
new
HashMap
<>(
varsCount
);
for
(
int
i
=
0
;
i
<
varsCount
;
i
++)
{
ArgType
currentTypeVar
=
currentVars
.
get
(
i
);
ArgType
resultType
=
parentTypeMap
!=
null
?
parentTypeMap
.
get
(
currentTypeVar
)
:
null
;
varsMap
.
put
(
sourceTypeVars
.
get
(
i
),
resultType
!=
null
?
resultType
:
currentTypeVar
);
}
map
.
put
(
type
.
getObject
(),
varsMap
);
}
});
List
<
ArgType
>
currentTypeVars
=
cls
.
getGenericTypeParameters
();
ClassTypeVarsAttr
typeVarsAttr
=
new
ClassTypeVarsAttr
(
currentTypeVars
,
map
);
cls
.
addAttr
(
typeVarsAttr
);
return
typeVarsAttr
;
}
public
void
visitSuperTypes
(
ArgType
type
,
BiConsumer
<
ArgType
,
ArgType
>
consumer
)
{
ClassNode
cls
=
root
.
resolveClass
(
type
);
if
(
cls
!=
null
)
{
cls
.
visitSuperTypes
(
consumer
);
}
else
{
ClspClass
clspClass
=
root
.
getClsp
().
getClsDetails
(
type
);
if
(
clspClass
!=
null
)
{
for
(
ArgType
superType
:
clspClass
.
getParents
())
{
if
(!
superType
.
equals
(
ArgType
.
OBJECT
))
{
consumer
.
accept
(
type
,
superType
);
visitSuperTypes
(
superType
,
consumer
);
}
}
}
}
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/methods/MutableMethodDetails.java
浏览文件 @
0541748e
...
@@ -86,6 +86,11 @@ public class MutableMethodDetails implements IMethodDetails {
...
@@ -86,6 +86,11 @@ public class MutableMethodDetails implements IMethodDetails {
this
.
accFlags
=
accFlags
;
this
.
accFlags
=
accFlags
;
}
}
@Override
public
String
toAttrString
()
{
return
IMethodDetails
.
super
.
toAttrString
()
+
" (mut)"
;
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"Mutable"
+
toAttrString
();
return
"Mutable"
+
toAttrString
();
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeBoundInvokeAssign.java
浏览文件 @
0541748e
...
@@ -2,7 +2,9 @@ package jadx.core.dex.visitors.typeinference;
...
@@ -2,7 +2,9 @@ package jadx.core.dex.visitors.typeinference;
import
jadx.core.dex.instructions.InvokeNode
;
import
jadx.core.dex.instructions.InvokeNode
;
import
jadx.core.dex.instructions.args.ArgType
;
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.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.IMethodDetails
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.nodes.RootNode
;
/**
/**
...
@@ -28,22 +30,34 @@ public final class TypeBoundInvokeAssign implements ITypeBoundDynamic {
...
@@ -28,22 +30,34 @@ public final class TypeBoundInvokeAssign implements ITypeBoundDynamic {
@Override
@Override
public
ArgType
getType
(
TypeUpdateInfo
updateInfo
)
{
public
ArgType
getType
(
TypeUpdateInfo
updateInfo
)
{
return
getReturnType
(
updateInfo
.
getType
(
invokeNode
.
getArg
(
0
)));
return
getReturnType
(
updateInfo
.
getType
(
getInstanceArg
(
)));
}
}
@Override
@Override
public
ArgType
getType
()
{
public
ArgType
getType
()
{
return
getReturnType
(
invokeNode
.
getArg
(
0
).
getType
());
return
getReturnType
(
getInstanceArg
(
).
getType
());
}
}
private
ArgType
getReturnType
(
ArgType
instanceType
)
{
private
ArgType
getReturnType
(
ArgType
instanceType
)
{
ArgType
resultGeneric
=
root
.
getTypeUtils
().
replaceClassGenerics
(
instanceType
,
genericReturnType
);
ArgType
mthDeclType
;
IMethodDetails
methodDetails
=
root
.
getMethodUtils
().
getMethodDetails
(
invokeNode
);
if
(
methodDetails
!=
null
)
{
// use methods detail to resolve declaration class for virtual invokes
mthDeclType
=
methodDetails
.
getMethodInfo
().
getDeclClass
().
getType
();
}
else
{
mthDeclType
=
instanceType
;
}
ArgType
resultGeneric
=
root
.
getTypeUtils
().
replaceClassGenerics
(
instanceType
,
mthDeclType
,
genericReturnType
);
if
(
resultGeneric
!=
null
&&
!
resultGeneric
.
isWildcard
())
{
if
(
resultGeneric
!=
null
&&
!
resultGeneric
.
isWildcard
())
{
return
resultGeneric
;
return
resultGeneric
;
}
}
return
invokeNode
.
getCallMth
().
getReturnType
();
return
invokeNode
.
getCallMth
().
getReturnType
();
}
}
private
InsnArg
getInstanceArg
()
{
return
invokeNode
.
getArg
(
0
);
}
@Override
@Override
public
RegisterArg
getArg
()
{
public
RegisterArg
getArg
()
{
return
invokeNode
.
getResult
();
return
invokeNode
.
getResult
();
...
@@ -71,7 +85,7 @@ public final class TypeBoundInvokeAssign implements ITypeBoundDynamic {
...
@@ -71,7 +85,7 @@ public final class TypeBoundInvokeAssign implements ITypeBoundDynamic {
return
"InvokeAssign{"
+
invokeNode
.
getCallMth
().
getShortId
()
return
"InvokeAssign{"
+
invokeNode
.
getCallMth
().
getShortId
()
+
", returnType="
+
genericReturnType
+
", returnType="
+
genericReturnType
+
", currentType="
+
getType
()
+
", currentType="
+
getType
()
+
", instanceArg="
+
invokeNode
.
getArg
(
0
)
+
", instanceArg="
+
getInstanceArg
(
)
+
'}'
;
+
'}'
;
}
}
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
浏览文件 @
0541748e
...
@@ -111,7 +111,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
...
@@ -111,7 +111,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
/**
/**
* Check if all types resolved
* Check if all types resolved
*/
*/
private
boolean
checkTypes
(
MethodNode
mth
)
{
private
static
boolean
checkTypes
(
MethodNode
mth
)
{
for
(
SSAVar
var
:
mth
.
getSVars
())
{
for
(
SSAVar
var
:
mth
.
getSVars
())
{
ArgType
type
=
var
.
getTypeInfo
().
getType
();
ArgType
type
=
var
.
getTypeInfo
().
getType
();
if
(!
type
.
isTypeKnown
())
{
if
(!
type
.
isTypeKnown
())
{
...
@@ -210,7 +210,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
...
@@ -210,7 +210,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
if
(
ssaVar
.
getTypeInfo
().
getType
().
equals
(
candidateType
))
{
if
(
ssaVar
.
getTypeInfo
().
getType
().
equals
(
candidateType
))
{
LOG
.
info
(
"Same type rejected: {} -> {}, bounds: {}"
,
ssaVar
,
candidateType
,
bounds
);
LOG
.
info
(
"Same type rejected: {} -> {}, bounds: {}"
,
ssaVar
,
candidateType
,
bounds
);
}
else
if
(
candidateType
.
isTypeKnown
())
{
}
else
if
(
candidateType
.
isTypeKnown
())
{
LOG
.
debug
(
"Type
set
rejected: {} -> {}, bounds: {}"
,
ssaVar
,
candidateType
,
bounds
);
LOG
.
debug
(
"Type rejected: {} -> {}, bounds: {}"
,
ssaVar
,
candidateType
,
bounds
);
}
}
}
}
return
false
;
return
false
;
...
@@ -512,7 +512,10 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
...
@@ -512,7 +512,10 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
private
int
tryInsertVarCast
(
MethodNode
mth
,
SSAVar
var
)
{
private
int
tryInsertVarCast
(
MethodNode
mth
,
SSAVar
var
)
{
for
(
ITypeBound
bound
:
var
.
getTypeInfo
().
getBounds
())
{
for
(
ITypeBound
bound
:
var
.
getTypeInfo
().
getBounds
())
{
ArgType
boundType
=
bound
.
getType
();
ArgType
boundType
=
bound
.
getType
();
if
(
boundType
.
isTypeKnown
()
&&
boundType
.
containsTypeVariable
())
{
if
(
boundType
.
isTypeKnown
()
&&
!
boundType
.
equals
(
var
.
getTypeInfo
().
getType
())
&&
boundType
.
containsTypeVariable
()
&&
!
root
.
getTypeUtils
().
containsUnknownTypeVar
(
mth
,
boundType
))
{
if
(
insertAssignCast
(
mth
,
var
,
boundType
))
{
if
(
insertAssignCast
(
mth
,
var
,
boundType
))
{
return
1
;
return
1
;
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java
浏览文件 @
0541748e
...
@@ -125,6 +125,16 @@ public final class TypeUpdate {
...
@@ -125,6 +125,16 @@ public final class TypeUpdate {
}
}
return
REJECT
;
return
REJECT
;
}
}
if
(
candidateType
.
containsTypeVariable
())
{
// reject unknown type vars
ArgType
unknownTypeVar
=
root
.
getTypeUtils
().
checkForUnknownTypeVars
(
updateInfo
.
getMth
(),
candidateType
);
if
(
unknownTypeVar
!=
null
)
{
if
(
Consts
.
DEBUG_TYPE_INFERENCE
)
{
LOG
.
debug
(
"Type rejected for {}: candidate: '{}' has unknown type var: '{}'"
,
arg
,
candidateType
,
unknownTypeVar
);
}
return
REJECT
;
}
}
}
}
if
(
arg
instanceof
RegisterArg
)
{
if
(
arg
instanceof
RegisterArg
)
{
RegisterArg
reg
=
(
RegisterArg
)
arg
;
RegisterArg
reg
=
(
RegisterArg
)
arg
;
...
...
jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics2.java
浏览文件 @
0541748e
...
@@ -6,15 +6,13 @@ import java.util.Map;
...
@@ -6,15 +6,13 @@ import java.util.Map;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.Test
;
import
jadx.NotYetImplemented
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
jadx.tests.api.IntegrationTest
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
public
class
TestGenerics2
extends
IntegrationTest
{
public
class
TestGenerics2
extends
IntegrationTest
{
@SuppressWarnings
(
"MismatchedQueryAndUpdateOfCollection"
)
public
static
class
TestCls
{
public
static
class
TestCls
{
public
static
class
ItemReference
<
V
>
extends
WeakReference
<
V
>
{
public
static
class
ItemReference
<
V
>
extends
WeakReference
<
V
>
{
public
Object
id
;
public
Object
id
;
...
@@ -40,22 +38,20 @@ public class TestGenerics2 extends IntegrationTest {
...
@@ -40,22 +38,20 @@ public class TestGenerics2 extends IntegrationTest {
@Test
@Test
public
void
test
()
{
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
assertThat
(
getClassNode
(
TestCls
.
class
))
String
code
=
cls
.
getCode
().
toString
();
.
code
()
.
containsOne
(
"public ItemReference(V item, Object objId, ReferenceQueue<? super V> queue) {"
)
assertThat
(
code
,
containsString
(
"public ItemReference(V item, Object objId, ReferenceQueue<? super V> queue) {"
));
.
containsOne
(
"public V get(Object id) {"
)
assertThat
(
code
,
containsString
(
"public V get(Object id) {"
));
.
containsOne
(
"WeakReference<V> ref = "
)
assertThat
(
code
,
containsString
(
"WeakReference<V> ref = "
));
.
containsOne
(
"return ref.get();"
);
assertThat
(
code
,
containsString
(
"return ref.get();"
));
}
}
@Test
@Test
@NotYetImplemented
(
"Make generic info propagation for methods (like Map.get)"
)
public
void
testDebug
()
{
public
void
testDebug
()
{
noDebugInfo
();
noDebugInfo
();
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
assertThat
(
getClassNode
(
TestCls
.
class
))
String
code
=
cls
.
getCode
().
toString
();
.
code
()
.
containsOne
(
"ItemReference<V> itemReference = this.items.get(obj);"
)
assertThat
(
code
,
containsString
(
"WeakReference<V> ref = "
)
);
.
containsOne
(
"return itemReference.get();"
);
}
}
}
}
jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics8.java
0 → 100644
浏览文件 @
0541748e
package
jadx.tests.integration.generics
;
import
java.util.Iterator
;
import
java.util.LinkedHashMap
;
import
org.junit.jupiter.api.Test
;
import
jadx.tests.api.IntegrationTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestGenerics8
extends
IntegrationTest
{
@SuppressWarnings
(
"IllegalType"
)
public
static
class
TestCls
<
I
>
extends
LinkedHashMap
<
I
,
Integer
>
implements
Iterable
<
I
>
{
@Override
public
Iterator
<
I
>
iterator
()
{
return
keySet
().
iterator
();
}
}
@Test
public
void
test
()
{
noDebugInfo
();
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
()
.
containsOne
(
"return keySet().iterator();"
);
}
}
jadx-core/src/test/java/jadx/tests/integration/generics/TestTypeVarsFromSuperClass.java
0 → 100644
浏览文件 @
0541748e
package
jadx.tests.integration.generics
;
import
java.util.Objects
;
import
org.junit.jupiter.api.Test
;
import
jadx.tests.api.IntegrationTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestTypeVarsFromSuperClass
extends
IntegrationTest
{
@SuppressWarnings
(
"ResultOfMethodCallIgnored"
)
public
static
class
TestCls
{
public
static
class
C1
<
A
>
{
}
public
static
class
C2
<
B
>
extends
C1
<
B
>
{
public
B
call
()
{
return
null
;
}
}
public
static
class
C3
<
C
>
extends
C2
<
C
>
{
}
public
static
class
C4
extends
C3
<
String
>
{
public
Object
test
()
{
String
str
=
call
();
Objects
.
nonNull
(
str
);
return
str
;
}
}
}
@Test
public
void
test
()
{
noDebugInfo
();
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
()
.
containsOne
(
"= call();"
)
.
doesNotContain
(
"(String)"
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录