Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
huluhong
jadx
提交
620a177c
J
jadx
项目概览
huluhong
/
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
620a177c
编写于
10月 08, 2022
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: restore enum class with custom code in static init (#1699)
上级
683c2dfb
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
129 addition
and
68 deletion
+129
-68
jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
...ore/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
+84
-68
jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithCustomInit.java
...jadx/tests/integration/enums/TestEnumsWithCustomInit.java
+45
-0
未找到文件。
jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
浏览文件 @
620a177c
...
...
@@ -37,6 +37,7 @@ import jadx.core.dex.instructions.mods.ConstructorInsn;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
...
...
@@ -48,7 +49,6 @@ import jadx.core.utils.BlockInsnPair;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.InsnRemover
;
import
jadx.core.utils.InsnUtils
;
import
jadx.core.utils.ListUtils
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
...
...
@@ -94,27 +94,26 @@ public class EnumVisitor extends AbstractVisitor {
@Override
public
boolean
visit
(
ClassNode
cls
)
throws
JadxException
{
boolean
converted
;
try
{
converted
=
convertToEnum
(
cls
);
}
catch
(
Exception
e
)
{
cls
.
addWarnComment
(
"Enum visitor error"
,
e
);
converted
=
false
;
}
if
(!
converted
)
{
AccessInfo
accessFlags
=
cls
.
getAccessFlags
();
if
(
accessFlags
.
isEnum
())
{
cls
.
setAccessFlags
(
accessFlags
.
remove
(
AccessFlags
.
ENUM
));
cls
.
addWarnComment
(
"Failed to restore enum class, 'enum' modifier and super class removed"
);
if
(
cls
.
isEnum
())
{
boolean
converted
;
try
{
converted
=
convertToEnum
(
cls
);
}
catch
(
Exception
e
)
{
cls
.
addWarnComment
(
"Enum visitor error"
,
e
);
converted
=
false
;
}
if
(!
converted
)
{
AccessInfo
accessFlags
=
cls
.
getAccessFlags
();
if
(
accessFlags
.
isEnum
())
{
cls
.
setAccessFlags
(
accessFlags
.
remove
(
AccessFlags
.
ENUM
));
cls
.
addWarnComment
(
"Failed to restore enum class, 'enum' modifier and super class removed"
);
}
}
}
return
true
;
}
private
boolean
convertToEnum
(
ClassNode
cls
)
{
if
(!
cls
.
isEnum
())
{
return
false
;
}
ArgType
superType
=
cls
.
getSuperClass
();
if
(
superType
!=
null
&&
superType
.
getObject
().
equals
(
ArgType
.
ENUM
.
getObject
()))
{
cls
.
add
(
AFlag
.
REMOVE_SUPER_CLASS
);
...
...
@@ -128,60 +127,34 @@ public class EnumVisitor extends AbstractVisitor {
if
(
staticRegion
==
null
||
classInitMth
.
getBasicBlocks
().
isEmpty
())
{
return
false
;
}
if
(!
ListUtils
.
allMatch
(
staticRegion
.
getSubBlocks
(),
BlockNode
.
class
::
isInstance
))
{
cls
.
addWarnComment
(
"Unexpected branching instructions in enum static init block"
);
return
false
;
}
List
<
BlockNode
>
staticBlocks
=
ListUtils
.
map
(
staticRegion
.
getSubBlocks
(),
BlockNode
.
class
::
cast
);
ArgType
clsType
=
cls
.
getClassInfo
().
getType
();
// search "$VALUES" field (holds all enum values)
List
<
FieldNode
>
valuesCandidates
=
cls
.
getFields
().
stream
()
.
filter
(
f
->
f
.
getAccessFlags
().
isStatic
())
.
filter
(
f
->
f
.
getType
().
isArray
())
.
filter
(
f
->
Objects
.
equals
(
f
.
getType
().
getArrayRootElement
(),
clsType
))
.
collect
(
Collectors
.
toList
());
if
(
valuesCandidates
.
isEmpty
())
{
return
false
;
}
if
(
valuesCandidates
.
size
()
>
1
)
{
valuesCandidates
.
removeIf
(
f
->
!
f
.
getAccessFlags
().
isSynthetic
());
}
if
(
valuesCandidates
.
size
()
>
1
)
{
Optional
<
FieldNode
>
valuesOpt
=
valuesCandidates
.
stream
().
filter
(
f
->
f
.
getName
().
equals
(
"$VALUES"
)).
findAny
();
if
(
valuesOpt
.
isPresent
())
{
valuesCandidates
.
clear
();
valuesCandidates
.
add
(
valuesOpt
.
get
());
// collect blocks on linear part of static method (ignore branching on method end)
List
<
BlockNode
>
staticBlocks
=
new
ArrayList
<>();
for
(
IContainer
subBlock
:
staticRegion
.
getSubBlocks
())
{
if
(
subBlock
instanceof
BlockNode
)
{
staticBlocks
.
add
((
BlockNode
)
subBlock
);
}
else
{
break
;
}
}
if
(
valuesCandidates
.
size
()
!=
1
)
{
cls
.
addWarnComment
(
"
Found several \"values\" enum fields: "
+
valuesCandidates
);
if
(
staticBlocks
.
isEmpty
()
)
{
cls
.
addWarnComment
(
"
Unexpected branching in enum static init block"
);
return
false
;
}
FieldNode
valuesField
=
valuesCandidates
.
get
(
0
);
// search "$VALUES" array init and collect enum fields
BlockInsnPair
valuesInitPair
=
getValuesInitInsn
(
classInitMth
,
valuesField
);
if
(
valuesInitPair
==
null
)
{
EnumData
data
=
new
EnumData
(
cls
,
classInitMth
,
staticBlocks
);
if
(!
searchValuesField
(
data
))
{
return
false
;
}
BlockNode
staticBlock
=
valuesInitPair
.
getBlock
();
InsnNode
valuesInitInsn
=
valuesInitPair
.
getInsn
();
EnumData
enumData
=
new
EnumData
(
cls
,
valuesField
,
staticBlocks
);
List
<
EnumField
>
enumFields
=
null
;
InsnArg
arrArg
=
valuesInitInsn
.
getArg
(
0
);
InsnArg
arrArg
=
data
.
valuesInitInsn
.
getArg
(
0
);
if
(
arrArg
.
isInsnWrap
())
{
InsnNode
wrappedInsn
=
((
InsnWrapArg
)
arrArg
).
getWrapInsn
();
enumFields
=
extractEnumFieldsFromInsn
(
enumD
ata
,
wrappedInsn
);
enumFields
=
extractEnumFieldsFromInsn
(
d
ata
,
wrappedInsn
);
}
if
(
enumFields
==
null
)
{
cls
.
addWarnComment
(
"Unknown enum class pattern. Please report as an issue!"
);
return
false
;
}
enumData
.
toRemove
.
add
(
valuesInitInsn
);
data
.
toRemove
.
add
(
data
.
valuesInitInsn
);
// all checks complete, perform transform
EnumClassAttr
attr
=
new
EnumClassAttr
(
enumFields
);
...
...
@@ -201,16 +174,56 @@ public class EnumVisitor extends AbstractVisitor {
fieldNode
.
getFieldInfo
().
setAlias
(
name
);
}
fieldNode
.
add
(
AFlag
.
DONT_GENERATE
);
processConstructorInsn
(
enumD
ata
,
enumField
,
classInitMth
);
processConstructorInsn
(
d
ata
,
enumField
,
classInitMth
);
}
valuesField
.
add
(
AFlag
.
DONT_GENERATE
);
InsnRemover
.
removeAllAndUnbind
(
classInitMth
,
enumD
ata
.
toRemove
);
data
.
valuesField
.
add
(
AFlag
.
DONT_GENERATE
);
InsnRemover
.
removeAllAndUnbind
(
classInitMth
,
d
ata
.
toRemove
);
if
(
classInitMth
.
countInsns
()
==
0
)
{
classInitMth
.
add
(
AFlag
.
DONT_GENERATE
);
}
else
if
(!
enumD
ata
.
toRemove
.
isEmpty
())
{
}
else
if
(!
d
ata
.
toRemove
.
isEmpty
())
{
CodeShrinkVisitor
.
shrinkMethod
(
classInitMth
);
}
removeEnumMethods
(
cls
,
clsType
,
valuesField
);
removeEnumMethods
(
cls
,
data
.
valuesField
);
return
true
;
}
/**
* Search "$VALUES" field (holds all enum values)
*/
private
boolean
searchValuesField
(
EnumData
data
)
{
ArgType
clsType
=
data
.
cls
.
getClassInfo
().
getType
();
List
<
FieldNode
>
valuesCandidates
=
data
.
cls
.
getFields
().
stream
()
.
filter
(
f
->
f
.
getAccessFlags
().
isStatic
())
.
filter
(
f
->
f
.
getType
().
isArray
())
.
filter
(
f
->
Objects
.
equals
(
f
.
getType
().
getArrayRootElement
(),
clsType
))
.
collect
(
Collectors
.
toList
());
if
(
valuesCandidates
.
isEmpty
())
{
data
.
cls
.
addWarnComment
(
"$VALUES field not found"
);
return
false
;
}
if
(
valuesCandidates
.
size
()
>
1
)
{
valuesCandidates
.
removeIf
(
f
->
!
f
.
getAccessFlags
().
isSynthetic
());
}
if
(
valuesCandidates
.
size
()
>
1
)
{
Optional
<
FieldNode
>
valuesOpt
=
valuesCandidates
.
stream
().
filter
(
f
->
f
.
getName
().
equals
(
"$VALUES"
)).
findAny
();
if
(
valuesOpt
.
isPresent
())
{
valuesCandidates
.
clear
();
valuesCandidates
.
add
(
valuesOpt
.
get
());
}
}
if
(
valuesCandidates
.
size
()
!=
1
)
{
data
.
cls
.
addWarnComment
(
"Found several \"values\" enum fields: "
+
valuesCandidates
);
return
false
;
}
data
.
valuesField
=
valuesCandidates
.
get
(
0
);
// search "$VALUES" array init and collect enum fields
BlockInsnPair
valuesInitPair
=
getValuesInitInsn
(
data
);
if
(
valuesInitPair
==
null
)
{
return
false
;
}
data
.
valuesInitInsn
=
valuesInitPair
.
getInsn
();
return
true
;
}
...
...
@@ -280,9 +293,9 @@ public class EnumVisitor extends AbstractVisitor {
return
enumFields
;
}
private
BlockInsnPair
getValuesInitInsn
(
MethodNode
classInitMth
,
FieldNode
valuesField
)
{
FieldInfo
searchField
=
valuesField
.
getFieldInfo
();
for
(
BlockNode
blockNode
:
classInitMth
.
getBasicBlocks
()
)
{
private
BlockInsnPair
getValuesInitInsn
(
EnumData
data
)
{
FieldInfo
searchField
=
data
.
valuesField
.
getFieldInfo
();
for
(
BlockNode
blockNode
:
data
.
staticBlocks
)
{
for
(
InsnNode
insn
:
blockNode
.
getInstructions
())
{
if
(
insn
.
getType
()
==
InsnType
.
SPUT
)
{
IndexInsnNode
indexInsnNode
=
(
IndexInsnNode
)
insn
;
...
...
@@ -449,7 +462,8 @@ public class EnumVisitor extends AbstractVisitor {
return
null
;
}
private
void
removeEnumMethods
(
ClassNode
cls
,
ArgType
clsType
,
FieldNode
valuesField
)
{
private
void
removeEnumMethods
(
ClassNode
cls
,
FieldNode
valuesField
)
{
ArgType
clsType
=
cls
.
getClassInfo
().
getType
();
String
valuesMethodShortId
=
"values()"
+
TypeGen
.
signature
(
ArgType
.
array
(
clsType
));
MethodNode
valuesMethod
=
null
;
// remove compiler generated methods
...
...
@@ -631,13 +645,15 @@ public class EnumVisitor extends AbstractVisitor {
private
static
class
EnumData
{
final
ClassNode
cls
;
final
FieldNode
valuesField
;
final
MethodNode
classInitMth
;
final
List
<
BlockNode
>
staticBlocks
;
final
List
<
InsnNode
>
toRemove
=
new
ArrayList
<>();
FieldNode
valuesField
;
InsnNode
valuesInitInsn
;
public
EnumData
(
ClassNode
cls
,
FieldNode
valuesField
,
List
<
BlockNode
>
staticBlocks
)
{
public
EnumData
(
ClassNode
cls
,
MethodNode
classInitMth
,
List
<
BlockNode
>
staticBlocks
)
{
this
.
cls
=
cls
;
this
.
valuesField
=
valuesField
;
this
.
classInitMth
=
classInitMth
;
this
.
staticBlocks
=
staticBlocks
;
}
}
...
...
jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithCustomInit.java
0 → 100644
浏览文件 @
620a177c
package
jadx.tests.integration.enums
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.junit.jupiter.api.Test
;
import
jadx.tests.api.IntegrationTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestEnumsWithCustomInit
extends
IntegrationTest
{
public
enum
TestCls
{
ONE
(
"I"
),
TWO
(
"II"
),
THREE
(
"III"
);
public
static
final
Map
<
String
,
TestCls
>
MAP
=
new
HashMap
<>();
static
{
for
(
TestCls
value
:
values
())
{
MAP
.
put
(
value
.
toString
(),
value
);
}
}
private
final
String
str
;
TestCls
(
String
str
)
{
this
.
str
=
str
;
}
public
String
toString
()
{
return
str
;
}
}
@Test
public
void
test
()
{
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
()
.
containsOne
(
"ONE(\"I\"),"
)
.
doesNotContain
(
"new TestEnumsWithCustomInit$TestCls("
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录