Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
极致猎手
jadx
提交
1a2e702b
J
jadx
项目概览
极致猎手
/
jadx
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jadx
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
1a2e702b
编写于
2月 14, 2022
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: inline nested anonymous classes (#1379)
上级
1da20b8e
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
309 addition
and
40 deletion
+309
-40
jadx-core/src/main/java/jadx/api/JavaClass.java
jadx-core/src/main/java/jadx/api/JavaClass.java
+6
-10
jadx-core/src/main/java/jadx/core/ProcessClass.java
jadx-core/src/main/java/jadx/core/ProcessClass.java
+2
-2
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
+1
-1
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+2
-2
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
+0
-1
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
+2
-2
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/AnonymousClassAttr.java
...va/jadx/core/dex/attributes/nodes/AnonymousClassAttr.java
+35
-0
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+11
-1
jadx-core/src/main/java/jadx/core/dex/visitors/AnonymousClassVisitor.java
...in/java/jadx/core/dex/visitors/AnonymousClassVisitor.java
+2
-1
jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
...ore/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
+2
-1
jadx-core/src/main/java/jadx/core/dex/visitors/ProcessAnonymous.java
...rc/main/java/jadx/core/dex/visitors/ProcessAnonymous.java
+69
-14
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
...core/dex/visitors/typeinference/TypeInferenceVisitor.java
+2
-2
jadx-core/src/main/java/jadx/core/utils/ListUtils.java
jadx-core/src/main/java/jadx/core/utils/ListUtils.java
+15
-3
jadx-core/src/test/java/jadx/tests/integration/inner/TestNestedAnonymousClass.java
...adx/tests/integration/inner/TestNestedAnonymousClass.java
+57
-0
jadx-core/src/test/smali/inner/TestNestedAnonymousClass/A.smali
...ore/src/test/smali/inner/TestNestedAnonymousClass/A.smali
+34
-0
jadx-core/src/test/smali/inner/TestNestedAnonymousClass/B.smali
...ore/src/test/smali/inner/TestNestedAnonymousClass/B.smali
+46
-0
jadx-core/src/test/smali/inner/TestNestedAnonymousClass/C.smali
...ore/src/test/smali/inner/TestNestedAnonymousClass/C.smali
+23
-0
未找到文件。
jadx-core/src/main/java/jadx/api/JavaClass.java
浏览文件 @
1a2e702b
...
...
@@ -11,6 +11,8 @@ import org.jetbrains.annotations.ApiStatus;
import
org.jetbrains.annotations.Nullable
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.AnonymousClassAttr
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.FieldNode
;
...
...
@@ -241,7 +243,7 @@ public final class JavaClass implements JavaNode {
@Override
public
JavaClass
getTopParentClass
()
{
if
(
cls
.
contains
(
A
Flag
.
ANONYMOUS_CLASS
))
{
if
(
cls
.
contains
(
A
Type
.
ANONYMOUS_CLASS
))
{
// moved to usage class
return
getParentForAnonymousClass
();
}
...
...
@@ -249,15 +251,9 @@ public final class JavaClass implements JavaNode {
}
private
JavaClass
getParentForAnonymousClass
()
{
List
<
JavaNode
>
useIn
=
getUseIn
();
if
(
useIn
.
isEmpty
())
{
return
this
;
}
JavaNode
useNode
=
useIn
.
get
(
0
);
if
(
useNode
.
equals
(
this
))
{
return
this
;
}
return
useNode
.
getTopParentClass
();
AnonymousClassAttr
attr
=
cls
.
get
(
AType
.
ANONYMOUS_CLASS
);
ClassNode
topParentClass
=
attr
.
getOuterCls
().
getTopParentClass
();
return
getRootDecompiler
().
convertClassNode
(
topParentClass
);
}
public
AccessInfo
getAccessInfo
()
{
...
...
jadx-core/src/main/java/jadx/core/ProcessClass.java
浏览文件 @
1a2e702b
...
...
@@ -34,11 +34,11 @@ public final class ProcessClass {
if
(
cls
.
contains
(
AFlag
.
CLASS_DEEP_RELOAD
))
{
cls
.
remove
(
AFlag
.
CLASS_DEEP_RELOAD
);
cls
.
deepUnload
();
cls
.
root
().
runPreDecompileStageForClass
(
cls
);
cls
.
add
(
AFlag
.
CLASS_UNLOADED
);
}
if
(
cls
.
contains
(
AFlag
.
CLASS_UNLOADED
))
{
cls
.
remove
(
AFlag
.
CLASS_UNLOADED
);
cls
.
root
().
runPreDecompileStageForClass
(
cls
);
cls
.
remove
(
AFlag
.
CLASS_UNLOADED
);
}
if
(
cls
.
getState
()
==
GENERATED_AND_UNLOADED
)
{
// force loading code again
...
...
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
浏览文件 @
1a2e702b
...
...
@@ -285,7 +285,7 @@ public class ClassGen {
private
boolean
isInnerClassesPresents
()
{
for
(
ClassNode
innerCls
:
cls
.
getInnerClasses
())
{
if
(!
innerCls
.
contains
(
A
Flag
.
ANONYMOUS_CLASS
))
{
if
(!
innerCls
.
contains
(
A
Type
.
ANONYMOUS_CLASS
))
{
return
true
;
}
}
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
浏览文件 @
1a2e702b
...
...
@@ -719,13 +719,13 @@ public class InsnGen {
private
void
inlineAnonymousConstructor
(
ICodeWriter
code
,
ClassNode
cls
,
ConstructorInsn
insn
)
throws
CodegenException
{
if
(
this
.
mth
.
getParentClass
()
==
cls
)
{
cls
.
remove
(
A
Flag
.
ANONYMOUS_CLASS
);
cls
.
remove
(
A
Type
.
ANONYMOUS_CLASS
);
cls
.
remove
(
AFlag
.
DONT_GENERATE
);
mth
.
getParentClass
().
getTopParentClass
().
add
(
AFlag
.
RESTART_CODEGEN
);
throw
new
CodegenException
(
"Anonymous inner class unlimited recursion detected."
+
" Convert class to inner: "
+
cls
.
getClassInfo
().
getFullName
());
}
ArgType
parent
=
cls
.
get
(
AType
.
ANONYMOUS_CLASS
_BASE
).
getBaseType
();
ArgType
parent
=
cls
.
get
(
AType
.
ANONYMOUS_CLASS
).
getBaseType
();
// hide empty anonymous constructors
for
(
MethodNode
ctor
:
cls
.
getMethods
())
{
if
(
ctor
.
contains
(
AFlag
.
ANONYMOUS_CONSTRUCTOR
)
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
浏览文件 @
1a2e702b
...
...
@@ -35,7 +35,6 @@ public enum AFlag {
SKIP_ARG
,
// skip argument in invoke call
NO_SKIP_ARGS
,
ANONYMOUS_CONSTRUCTOR
,
ANONYMOUS_CLASS
,
THIS
,
SUPER
,
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AType.java
浏览文件 @
1a2e702b
...
...
@@ -2,7 +2,7 @@ package jadx.core.dex.attributes;
import
jadx.api.plugins.input.data.attributes.IJadxAttrType
;
import
jadx.api.plugins.input.data.attributes.IJadxAttribute
;
import
jadx.core.dex.attributes.nodes.AnonymousClass
Base
Attr
;
import
jadx.core.dex.attributes.nodes.AnonymousClassAttr
;
import
jadx.core.dex.attributes.nodes.ClassTypeVarsAttr
;
import
jadx.core.dex.attributes.nodes.DeclareVariablesAttr
;
import
jadx.core.dex.attributes.nodes.EdgeInsnAttr
;
...
...
@@ -54,7 +54,7 @@ public final class AType<T extends IJadxAttribute> implements IJadxAttrType<T> {
public
static
final
AType
<
EnumClassAttr
>
ENUM_CLASS
=
new
AType
<>();
public
static
final
AType
<
EnumMapAttr
>
ENUM_MAP
=
new
AType
<>();
public
static
final
AType
<
ClassTypeVarsAttr
>
CLASS_TYPE_VARS
=
new
AType
<>();
public
static
final
AType
<
AnonymousClass
BaseAttr
>
ANONYMOUS_CLASS_BASE
=
new
AType
<>();
public
static
final
AType
<
AnonymousClass
Attr
>
ANONYMOUS_CLASS
=
new
AType
<>();
// field
public
static
final
AType
<
FieldInitInsnAttr
>
FIELD_INIT_INSN
=
new
AType
<>();
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/AnonymousClass
Base
Attr.java
→
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/AnonymousClassAttr.java
浏览文件 @
1a2e702b
...
...
@@ -3,26 +3,33 @@ package jadx.core.dex.attributes.nodes;
import
jadx.api.plugins.input.data.attributes.PinnedAttribute
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.ClassNode
;
public
class
AnonymousClass
Base
Attr
extends
PinnedAttribute
{
public
class
AnonymousClassAttr
extends
PinnedAttribute
{
private
final
ClassNode
outerCls
;
private
final
ArgType
baseType
;
public
AnonymousClassBaseAttr
(
ArgType
baseType
)
{
public
AnonymousClassAttr
(
ClassNode
outerCls
,
ArgType
baseType
)
{
this
.
outerCls
=
outerCls
;
this
.
baseType
=
baseType
;
}
public
ClassNode
getOuterCls
()
{
return
outerCls
;
}
public
ArgType
getBaseType
()
{
return
baseType
;
}
@Override
public
AType
<
AnonymousClass
Base
Attr
>
getAttrType
()
{
return
AType
.
ANONYMOUS_CLASS
_BASE
;
public
AType
<
AnonymousClassAttr
>
getAttrType
()
{
return
AType
.
ANONYMOUS_CLASS
;
}
@Override
public
String
toString
()
{
return
"AnonymousClass
BaseAttr{
"
+
baseType
+
'}'
;
return
"AnonymousClass
{"
+
outerCls
+
", base:
"
+
baseType
+
'}'
;
}
}
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
浏览文件 @
1a2e702b
...
...
@@ -33,6 +33,7 @@ import jadx.api.plugins.input.data.impl.ListConsumer;
import
jadx.core.Consts
;
import
jadx.core.ProcessClass
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.NotificationAttrNode
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.info.AccessInfo.AFType
;
...
...
@@ -42,6 +43,7 @@ import jadx.core.dex.info.MethodInfo;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.nodes.utils.TypeUtils
;
import
jadx.core.utils.ListUtils
;
import
jadx.core.utils.Utils
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
...
...
@@ -619,7 +621,7 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
}
public
boolean
isAnonymous
()
{
return
contains
(
A
Flag
.
ANONYMOUS_CLASS
);
return
contains
(
A
Type
.
ANONYMOUS_CLASS
);
}
public
boolean
isInner
()
{
...
...
@@ -750,6 +752,10 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
this
.
dependencies
=
dependencies
;
}
public
void
removeDependency
(
ClassNode
dep
)
{
this
.
dependencies
=
ListUtils
.
safeRemoveAndTrim
(
this
.
dependencies
,
dep
);
}
public
List
<
ClassNode
>
getCodegenDeps
()
{
return
codegenDeps
;
}
...
...
@@ -758,6 +764,10 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
this
.
codegenDeps
=
codegenDeps
;
}
public
void
addCodegenDep
(
ClassNode
dep
)
{
this
.
codegenDeps
=
ListUtils
.
safeAdd
(
this
.
codegenDeps
,
dep
);
}
public
int
getTotalDepsCount
()
{
return
dependencies
.
size
()
+
codegenDeps
.
size
();
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/AnonymousClassVisitor.java
浏览文件 @
1a2e702b
...
...
@@ -7,6 +7,7 @@ import java.util.List;
import
java.util.Map
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.FieldReplaceAttr
;
import
jadx.core.dex.attributes.nodes.SkipMethodArgsAttr
;
import
jadx.core.dex.info.FieldInfo
;
...
...
@@ -36,7 +37,7 @@ public class AnonymousClassVisitor extends AbstractVisitor {
@Override
public
boolean
visit
(
ClassNode
cls
)
throws
JadxException
{
if
(
cls
.
contains
(
A
Flag
.
ANONYMOUS_CLASS
))
{
if
(
cls
.
contains
(
A
Type
.
ANONYMOUS_CLASS
))
{
for
(
MethodNode
mth
:
cls
.
getMethods
())
{
if
(
mth
.
contains
(
AFlag
.
ANONYMOUS_CONSTRUCTOR
))
{
processAnonymousConstructor
(
mth
);
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java
浏览文件 @
1a2e702b
...
...
@@ -15,6 +15,7 @@ import jadx.api.plugins.input.data.AccessFlags;
import
jadx.core.codegen.TypeGen
;
import
jadx.core.deobf.NameMapper
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.EnumClassAttr
;
import
jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField
;
import
jadx.core.dex.attributes.nodes.SkipMethodArgsAttr
;
...
...
@@ -389,7 +390,7 @@ public class EnumVisitor extends AbstractVisitor {
}
if
(
constrCls
.
equals
(
cls
))
{
// allow same class
}
else
if
(
constrCls
.
contains
(
A
Flag
.
ANONYMOUS_CLASS
))
{
}
else
if
(
constrCls
.
contains
(
A
Type
.
ANONYMOUS_CLASS
))
{
// allow external class already marked as anonymous
}
else
{
return
null
;
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ProcessAnonymous.java
浏览文件 @
1a2e702b
package
jadx.core.dex.visitors
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.jetbrains.annotations.Nullable
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.nodes.AnonymousClassBaseAttr
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.AnonymousClassAttr
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.ClassNode
;
...
...
@@ -25,20 +29,32 @@ import jadx.core.utils.exceptions.JadxException;
)
public
class
ProcessAnonymous
extends
AbstractVisitor
{
private
boolean
inlineAnonymous
;
private
boolean
inlineAnonymous
Classes
;
@Override
public
void
init
(
RootNode
root
)
{
inlineAnonymous
=
root
.
getArgs
().
isInlineAnonymousClasses
();
inlineAnonymousClasses
=
root
.
getArgs
().
isInlineAnonymousClasses
();
if
(!
inlineAnonymousClasses
)
{
return
;
}
for
(
ClassNode
cls
:
root
.
getClasses
())
{
markAnonymousClass
(
cls
);
}
mergeAnonymousDeps
(
root
);
}
@Override
public
boolean
visit
(
ClassNode
cls
)
throws
JadxException
{
if
(!
inlineAnonymous
)
{
return
false
;
if
(
inlineAnonymousClasses
&&
cls
.
contains
(
AFlag
.
CLASS_UNLOADED
))
{
// enter only on class reload
visitClassAndInners
(
cls
);
}
return
false
;
}
private
void
visitClassAndInners
(
ClassNode
cls
)
{
markAnonymousClass
(
cls
);
return
true
;
cls
.
getInnerClasses
().
forEach
(
this
::
visitClassAndInners
)
;
}
private
static
void
markAnonymousClass
(
ClassNode
cls
)
{
...
...
@@ -53,25 +69,64 @@ public class ProcessAnonymous extends AbstractVisitor {
if
(
baseType
==
null
)
{
return
;
}
cls
.
add
(
AFlag
.
ANONYMOUS_CLASS
);
cls
.
addAttr
(
new
AnonymousClassBaseAttr
(
baseType
));
ClassNode
outerCls
=
anonymousConstructor
.
getUseIn
().
get
(
0
).
getParentClass
();
cls
.
addAttr
(
new
AnonymousClassAttr
(
outerCls
,
baseType
));
cls
.
add
(
AFlag
.
DONT_GENERATE
);
anonymousConstructor
.
add
(
AFlag
.
ANONYMOUS_CONSTRUCTOR
);
// force anonymous class to be processed before outer class,
// actual usage of outer class will be removed at anonymous class process,
// see ModVisitor.processAnonymousConstructor method
ClassNode
outerCls
=
anonymousConstructor
.
getUseIn
().
get
(
0
).
getParentClass
();
ClassNode
topOuterCls
=
outerCls
.
getTopParentClass
();
ListUtils
.
safeRemove
(
cls
.
getDependencies
(),
topOuterCls
);
cls
.
removeDependency
(
topOuterCls
);
ListUtils
.
safeRemove
(
outerCls
.
getUseIn
(),
cls
);
// move dependency to codegen stage
if
(
cls
.
isTopClass
())
{
topOuterCls
.
setDependencies
(
ListUtils
.
safeRemoveAndTrim
(
topOuterCls
.
getDependencies
(),
cls
));
topOuterCls
.
setCodegenDeps
(
ListUtils
.
safeAdd
(
topOuterCls
.
getCodegenDeps
(),
cls
));
topOuterCls
.
removeDependency
(
cls
);
topOuterCls
.
addCodegenDep
(
cls
);
}
}
private
void
mergeAnonymousDeps
(
RootNode
root
)
{
// Collect edges to build bidirectional tree:
// inline edge: anonymous -> outer (one-to-one)
// use edges: outer -> *anonymous (one-to-many)
Map
<
ClassNode
,
ClassNode
>
inlineMap
=
new
HashMap
<>();
Map
<
ClassNode
,
List
<
ClassNode
>>
useMap
=
new
HashMap
<>();
for
(
ClassNode
anonymousCls
:
root
.
getClasses
())
{
AnonymousClassAttr
attr
=
anonymousCls
.
get
(
AType
.
ANONYMOUS_CLASS
);
if
(
attr
!=
null
)
{
ClassNode
outerCls
=
attr
.
getOuterCls
();
useMap
.
computeIfAbsent
(
outerCls
,
k
->
new
ArrayList
<>()).
add
(
anonymousCls
);
useMap
.
putIfAbsent
(
anonymousCls
,
new
ArrayList
<>());
// put leaf explicitly
inlineMap
.
put
(
anonymousCls
,
outerCls
);
}
}
if
(
inlineMap
.
isEmpty
())
{
return
;
}
// starting from leaf process deps in nodes up to root
useMap
.
forEach
((
key
,
list
)
->
{
if
(
list
.
isEmpty
())
{
updateDeps
(
key
,
inlineMap
);
}
});
}
private
void
updateDeps
(
ClassNode
leafCls
,
Map
<
ClassNode
,
ClassNode
>
inlineMap
)
{
List
<
ClassNode
>
list
=
new
ArrayList
<>();
ClassNode
current
=
leafCls
;
while
(
current
!=
null
)
{
list
.
add
(
current
.
getTopParentClass
());
current
=
inlineMap
.
get
(
current
);
}
if
(
list
.
size
()
<=
2
)
{
// first level deps already processed
return
;
}
ClassNode
topNode
=
list
.
remove
(
list
.
size
()
-
1
);
topNode
.
setCodegenDeps
(
ListUtils
.
distinctMergeSortedLists
(
topNode
.
getCodegenDeps
(),
list
));
}
private
static
boolean
canBeAnonymous
(
ClassNode
cls
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
浏览文件 @
1a2e702b
...
...
@@ -19,7 +19,7 @@ import jadx.core.Consts;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.AnonymousClass
Base
Attr
;
import
jadx.core.dex.attributes.nodes.AnonymousClassAttr
;
import
jadx.core.dex.attributes.nodes.PhiListAttr
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.instructions.ArithNode
;
...
...
@@ -321,7 +321,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
if
(
ctr
.
isNewInstance
())
{
ClassNode
ctrCls
=
root
.
resolveClass
(
ctr
.
getClassType
());
if
(
ctrCls
!=
null
&&
ctrCls
.
contains
(
AFlag
.
DONT_GENERATE
))
{
AnonymousClass
BaseAttr
baseTypeAttr
=
ctrCls
.
get
(
AType
.
ANONYMOUS_CLASS_BASE
);
AnonymousClass
Attr
baseTypeAttr
=
ctrCls
.
get
(
AType
.
ANONYMOUS_CLASS
);
if
(
baseTypeAttr
!=
null
)
{
return
baseTypeAttr
.
getBaseType
();
}
...
...
jadx-core/src/main/java/jadx/core/utils/ListUtils.java
浏览文件 @
1a2e702b
...
...
@@ -6,13 +6,13 @@ import java.util.Collections;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
import
java.util.TreeSet
;
import
java.util.function.Function
;
import
java.util.function.Predicate
;
import
org.jetbrains.annotations.Nullable
;
import
jadx.core.dex.nodes.BlockNode
;
public
class
ListUtils
{
public
static
<
T
>
boolean
isSingleElement
(
@Nullable
List
<
T
>
list
,
T
obj
)
{
...
...
@@ -48,7 +48,19 @@ public class ListUtils {
return
list
.
get
(
list
.
size
()
-
1
);
}
public
static
List
<
BlockNode
>
distinctList
(
List
<
BlockNode
>
list
)
{
public
static
<
T
extends
Comparable
<
T
>>
List
<
T
>
distinctMergeSortedLists
(
List
<
T
>
first
,
List
<
T
>
second
)
{
if
(
first
.
isEmpty
())
{
return
second
;
}
if
(
second
.
isEmpty
())
{
return
first
;
}
Set
<
T
>
set
=
new
TreeSet
<>(
first
);
set
.
addAll
(
second
);
return
new
ArrayList
<>(
set
);
}
public
static
<
T
>
List
<
T
>
distinctList
(
List
<
T
>
list
)
{
return
new
ArrayList
<>(
new
LinkedHashSet
<>(
list
));
}
...
...
jadx-core/src/test/java/jadx/tests/integration/inner/TestNestedAnonymousClass.java
0 → 100644
浏览文件 @
1a2e702b
package
jadx.tests.integration.inner
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.concurrent.Callable
;
import
org.junit.jupiter.api.Test
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.SmaliTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestNestedAnonymousClass
extends
SmaliTest
{
@SuppressWarnings
(
"Convert2Lambda"
)
public
static
class
TestCls
{
public
void
test
()
{
use
(
new
Callable
<
Runnable
>()
{
@Override
public
Runnable
call
()
{
return
new
Runnable
()
{
@Override
public
void
run
()
{
System
.
out
.
println
(
"run"
);
}
};
}
});
}
public
void
testLambda
()
{
use
(()
->
()
->
System
.
out
.
println
(
"lambda"
));
}
public
void
use
(
Callable
<
Runnable
>
r
)
{
}
}
@Test
public
void
test
()
{
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
()
.
containsOne
(
"use(new Callable<Runnable>() {"
)
.
containsOne
(
"return new Runnable() {"
);
}
@Test
public
void
testSmali
()
{
getArgs
().
setRenameFlags
(
Collections
.
emptySet
());
List
<
ClassNode
>
classes
=
loadFromSmaliFiles
();
assertThat
(
searchCls
(
classes
,
"A"
))
.
code
()
.
containsOne
(
"use(new Callable<Runnable>() {"
)
.
containsOne
(
"return new Runnable() {"
);
}
}
jadx-core/src/test/smali/inner/TestNestedAnonymousClass/A.smali
0 → 100644
浏览文件 @
1a2e702b
.class public Linner/A;
.super Ljava/lang/Object;
.method public constructor <init>()V
.registers 1
.prologue
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public test()V
.registers 2
.prologue
new-instance v0, Linner/B;
invoke-direct {v0, p0}, Linner/B;-><init>(Linner/A;)V
invoke-virtual {p0, v0}, Linner/A;->use(Ljava/util/concurrent/Callable;)V
return-void
.end method
.method public use(Ljava/util/concurrent/Callable;)V
.registers 2
.annotation system Ldalvik/annotation/Signature;
value = {
"(",
"Ljava/util/concurrent/Callable",
"<",
"Ljava/lang/Runnable;",
">;)V"
}
.end annotation
.prologue
return-void
.end method
jadx-core/src/test/smali/inner/TestNestedAnonymousClass/B.smali
0 → 100644
浏览文件 @
1a2e702b
.class synthetic Linner/B;
.super Ljava/lang/Object;
.implements Ljava/util/concurrent/Callable;
.annotation system Ldalvik/annotation/Signature;
value = {
"Ljava/lang/Object;",
"Ljava/util/concurrent/Callable",
"<",
"Ljava/lang/Runnable;",
">;"
}
.end annotation
.field final synthetic this$0:Linner/A;
.method constructor <init>(Linner/A;)V
.registers 2
.prologue
iput-object p1, p0, Linner/B;->this$0:Linner/A;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public bridge synthetic call()Ljava/lang/Object;
.registers 2
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/lang/Exception;
}
.end annotation
.prologue
invoke-virtual {p0}, Linner/B;->call()Ljava/lang/Runnable;
move-result-object v0
return-object v0
.end method
.method public call()Ljava/lang/Runnable;
.registers 2
.prologue
new-instance v0, Linner/C;
invoke-direct {v0, p0}, Linner/C;-><init>(Linner/B;)V
return-object v0
.end method
jadx-core/src/test/smali/inner/TestNestedAnonymousClass/C.smali
0 → 100644
浏览文件 @
1a2e702b
.class synthetic Linner/C;
.super Ljava/lang/Object;
.implements Ljava/lang/Runnable;
.field final synthetic this$1:Linner/B;
.method constructor <init>(Linner/B;)V
.registers 2
.prologue
iput-object p1, p0, Linner/C;->this$1:Linner/B;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public run()V
.registers 3
.prologue
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "run"
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
return-void
.end method
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录