Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
keyescgm
jadx
提交
157e702f
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
157e702f
编写于
3月 23, 2023
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: inline lambdas by instance field (#1800)
上级
77892f41
变更
23
隐藏空白更改
内联
并排
Showing
23 changed file
with
200 addition
and
58 deletion
+200
-58
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
+8
-0
jadx-core/src/main/java/jadx/api/JadxArgs.java
jadx-core/src/main/java/jadx/api/JadxArgs.java
+9
-0
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+28
-7
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
+1
-1
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
+2
-0
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/AnonymousClassAttr.java
...va/jadx/core/dex/attributes/nodes/AnonymousClassAttr.java
+13
-2
jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java
jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java
+13
-0
jadx-core/src/main/java/jadx/core/dex/visitors/ExtractFieldInit.java
...rc/main/java/jadx/core/dex/visitors/ExtractFieldInit.java
+8
-2
jadx-core/src/main/java/jadx/core/dex/visitors/ProcessAnonymous.java
...rc/main/java/jadx/core/dex/visitors/ProcessAnonymous.java
+73
-12
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
...core/dex/visitors/typeinference/TypeInferenceVisitor.java
+1
-1
jadx-core/src/test/java/jadx/tests/integration/inline/TestInstanceLambda.java
...ava/jadx/tests/integration/inline/TestInstanceLambda.java
+17
-12
jadx-core/src/test/smali/inline/TestInstanceLambda/Lambda.smali
...ore/src/test/smali/inline/TestInstanceLambda/Lambda.smali
+5
-5
jadx-core/src/test/smali/inline/TestInstanceLambda/TestCls.smali
...re/src/test/smali/inline/TestInstanceLambda/TestCls.smali
+2
-16
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
+4
-0
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
...i/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
+8
-0
jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties
jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties
jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties
jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
+1
-0
jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties
jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties
+1
-0
未找到文件。
jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
浏览文件 @
157e702f
...
...
@@ -91,6 +91,9 @@ public class JadxCLIArgs {
@Parameter
(
names
=
{
"--no-inline-methods"
},
description
=
"disable methods inline"
)
protected
boolean
inlineMethods
=
true
;
@Parameter
(
names
=
{
"--no-inline-kotlin-lambda"
},
description
=
"disable inline for Kotlin lambdas"
)
protected
boolean
allowInlineKotlinLambda
=
true
;
@Parameter
(
names
=
"--no-finally"
,
description
=
"don't extract finally block"
)
protected
boolean
extractFinally
=
true
;
...
...
@@ -287,6 +290,7 @@ public class JadxCLIArgs {
args
.
setInsertDebugLines
(
addDebugLines
);
args
.
setInlineAnonymousClasses
(
inlineAnonymousClasses
);
args
.
setInlineMethods
(
inlineMethods
);
args
.
setAllowInlineKotlinLambda
(
allowInlineKotlinLambda
);
args
.
setExtractFinally
(
extractFinally
);
args
.
setRenameFlags
(
renameFlags
);
args
.
setFsCaseSensitive
(
fsCaseSensitive
);
...
...
@@ -368,6 +372,10 @@ public class JadxCLIArgs {
return
inlineMethods
;
}
public
boolean
isAllowInlineKotlinLambda
()
{
return
allowInlineKotlinLambda
;
}
public
boolean
isExtractFinally
()
{
return
extractFinally
;
}
...
...
jadx-core/src/main/java/jadx/api/JadxArgs.java
浏览文件 @
157e702f
...
...
@@ -53,6 +53,7 @@ public class JadxArgs {
private
boolean
extractFinally
=
true
;
private
boolean
inlineAnonymousClasses
=
true
;
private
boolean
inlineMethods
=
true
;
private
boolean
allowInlineKotlinLambda
=
true
;
private
boolean
skipResources
=
false
;
private
boolean
skipSources
=
false
;
...
...
@@ -263,6 +264,14 @@ public class JadxArgs {
this
.
inlineMethods
=
inlineMethods
;
}
public
boolean
isAllowInlineKotlinLambda
()
{
return
allowInlineKotlinLambda
;
}
public
void
setAllowInlineKotlinLambda
(
boolean
allowInlineKotlinLambda
)
{
this
.
allowInlineKotlinLambda
=
allowInlineKotlinLambda
;
}
public
boolean
isExtractFinally
()
{
return
extractFinally
;
}
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
浏览文件 @
157e702f
...
...
@@ -17,6 +17,7 @@ import jadx.api.plugins.input.data.MethodHandleType;
import
jadx.api.plugins.input.data.annotations.EncodedValue
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.FieldInitInsnAttr
;
import
jadx.core.dex.attributes.nodes.FieldReplaceAttr
;
import
jadx.core.dex.attributes.nodes.GenericInfoAttr
;
import
jadx.core.dex.attributes.nodes.LoopLabelAttr
;
...
...
@@ -210,7 +211,31 @@ public class InsnGen {
}
}
protected
void
staticField
(
ICodeWriter
code
,
FieldInfo
field
)
throws
CodegenException
{
FieldNode
fieldNode
=
root
.
resolveField
(
field
);
if
(
fieldNode
!=
null
&&
fieldNode
.
contains
(
AFlag
.
INLINE_INSTANCE_FIELD
)
&&
fieldNode
.
getParentClass
().
contains
(
AType
.
ANONYMOUS_CLASS
))
{
FieldInitInsnAttr
initInsnAttr
=
fieldNode
.
get
(
AType
.
FIELD_INIT_INSN
);
if
(
initInsnAttr
!=
null
)
{
InsnNode
insn
=
initInsnAttr
.
getInsn
();
if
(
insn
instanceof
ConstructorInsn
)
{
fieldNode
.
add
(
AFlag
.
DONT_GENERATE
);
inlineAnonymousConstructor
(
code
,
fieldNode
.
getParentClass
(),
(
ConstructorInsn
)
insn
);
return
;
}
}
}
makeStaticFieldAccess
(
code
,
field
,
fieldNode
,
mgen
.
getClassGen
());
}
public
static
void
makeStaticFieldAccess
(
ICodeWriter
code
,
FieldInfo
field
,
ClassGen
clsGen
)
{
FieldNode
fieldNode
=
clsGen
.
getClassNode
().
root
().
resolveField
(
field
);
makeStaticFieldAccess
(
code
,
field
,
fieldNode
,
clsGen
);
}
private
static
void
makeStaticFieldAccess
(
ICodeWriter
code
,
FieldInfo
field
,
@Nullable
FieldNode
fieldNode
,
ClassGen
clsGen
)
{
ClassInfo
declClass
=
field
.
getDeclClass
();
// TODO
boolean
fieldFromThisClass
=
clsGen
.
getClassNode
().
getClassInfo
().
equals
(
declClass
);
...
...
@@ -221,7 +246,6 @@ public class InsnGen {
}
code
.
add
(
'.'
);
}
FieldNode
fieldNode
=
clsGen
.
getClassNode
().
root
().
resolveField
(
field
);
if
(
fieldNode
!=
null
)
{
code
.
attachAnnotation
(
fieldNode
);
}
...
...
@@ -232,10 +256,6 @@ public class InsnGen {
}
}
protected
void
staticField
(
ICodeWriter
code
,
FieldInfo
field
)
{
makeStaticFieldAccess
(
code
,
field
,
mgen
.
getClassGen
());
}
public
void
useClass
(
ICodeWriter
code
,
ArgType
type
)
{
mgen
.
getClassGen
().
useClass
(
code
,
type
);
}
...
...
@@ -695,9 +715,7 @@ public class InsnGen {
private
void
makeConstructor
(
ConstructorInsn
insn
,
ICodeWriter
code
)
throws
CodegenException
{
ClassNode
cls
=
mth
.
root
().
resolveClass
(
insn
.
getClassType
());
if
(
cls
!=
null
&&
cls
.
isAnonymous
()
&&
!
fallback
)
{
cls
.
ensureProcessed
();
inlineAnonymousConstructor
(
code
,
cls
,
insn
);
mth
.
getParentClass
().
addInlinedClass
(
cls
);
return
;
}
if
(
insn
.
isSelf
())
{
...
...
@@ -748,6 +766,7 @@ public class InsnGen {
}
private
void
inlineAnonymousConstructor
(
ICodeWriter
code
,
ClassNode
cls
,
ConstructorInsn
insn
)
throws
CodegenException
{
cls
.
ensureProcessed
();
if
(
this
.
mth
.
getParentClass
()
==
cls
)
{
cls
.
remove
(
AType
.
ANONYMOUS_CLASS
);
cls
.
remove
(
AFlag
.
DONT_GENERATE
);
...
...
@@ -786,6 +805,8 @@ public class InsnGen {
ClassGen
classGen
=
new
ClassGen
(
cls
,
mgen
.
getClassGen
().
getParentGen
());
classGen
.
setOuterNameGen
(
mgen
.
getNameGen
());
classGen
.
addClassBody
(
code
,
true
);
mth
.
getParentClass
().
addInlinedClass
(
cls
);
}
private
void
makeInvoke
(
InvokeNode
insn
,
ICodeWriter
code
)
throws
CodegenException
{
...
...
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
浏览文件 @
157e702f
...
...
@@ -270,7 +270,7 @@ public class RegionGen extends InsnGen {
code
.
startLine
(
'}'
);
}
private
void
addCaseKey
(
ICodeWriter
code
,
InsnArg
arg
,
Object
k
)
{
private
void
addCaseKey
(
ICodeWriter
code
,
InsnArg
arg
,
Object
k
)
throws
CodegenException
{
if
(
k
instanceof
FieldNode
)
{
FieldNode
fn
=
(
FieldNode
)
k
;
if
(
fn
.
getParentClass
().
isEnum
())
{
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
浏览文件 @
157e702f
...
...
@@ -37,7 +37,9 @@ public enum AFlag {
SKIP_FIRST_ARG
,
SKIP_ARG
,
// skip argument in invoke call
NO_SKIP_ARGS
,
ANONYMOUS_CONSTRUCTOR
,
INLINE_INSTANCE_FIELD
,
THIS
,
SUPER
,
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/AnonymousClassAttr.java
浏览文件 @
157e702f
...
...
@@ -7,12 +7,19 @@ import jadx.core.dex.nodes.ClassNode;
public
class
AnonymousClassAttr
extends
PinnedAttribute
{
public
enum
InlineType
{
CONSTRUCTOR
,
INSTANCE_FIELD
,
}
private
final
ClassNode
outerCls
;
private
final
ArgType
baseType
;
private
final
InlineType
inlineType
;
public
AnonymousClassAttr
(
ClassNode
outerCls
,
ArgType
baseType
)
{
public
AnonymousClassAttr
(
ClassNode
outerCls
,
ArgType
baseType
,
InlineType
inlineType
)
{
this
.
outerCls
=
outerCls
;
this
.
baseType
=
baseType
;
this
.
inlineType
=
inlineType
;
}
public
ClassNode
getOuterCls
()
{
...
...
@@ -23,6 +30,10 @@ public class AnonymousClassAttr extends PinnedAttribute {
return
baseType
;
}
public
InlineType
getInlineType
()
{
return
inlineType
;
}
@Override
public
AType
<
AnonymousClassAttr
>
getAttrType
()
{
return
AType
.
ANONYMOUS_CLASS
;
...
...
@@ -30,6 +41,6 @@ public class AnonymousClassAttr extends PinnedAttribute {
@Override
public
String
toString
()
{
return
"AnonymousClass{"
+
outerCls
+
", base: "
+
baseType
+
'}'
;
return
"AnonymousClass{"
+
outerCls
+
", base: "
+
baseType
+
", inline type: "
+
inlineType
+
'}'
;
}
}
jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java
浏览文件 @
157e702f
package
jadx.core.dex.info
;
import
org.intellij.lang.annotations.MagicConstant
;
import
jadx.api.plugins.input.data.AccessFlags
;
import
jadx.core.Consts
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
...
...
@@ -20,10 +22,21 @@ public class AccessInfo {
this
.
type
=
type
;
}
@MagicConstant
(
valuesFromClass
=
AccessFlags
.
class
)
public
boolean
containsFlag
(
int
flag
)
{
return
(
accFlags
&
flag
)
!=
0
;
}
@MagicConstant
(
valuesFromClass
=
AccessFlags
.
class
)
public
boolean
containsFlags
(
int
...
flags
)
{
for
(
int
flag
:
flags
)
{
if
((
accFlags
&
flag
)
==
0
)
{
return
false
;
}
}
return
true
;
}
public
AccessInfo
remove
(
int
flag
)
{
if
(
containsFlag
(
flag
))
{
return
new
AccessInfo
(
accFlags
&
~
flag
,
type
);
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ExtractFieldInit.java
浏览文件 @
157e702f
...
...
@@ -384,8 +384,14 @@ public class ExtractFieldInit extends AbstractVisitor {
return
list
;
}
private
static
void
addFieldInitAttr
(
MethodNode
mth
,
FieldNode
field
,
InsnNode
insn
)
{
InsnNode
assignInsn
=
InsnNode
.
wrapArg
(
insn
.
getArg
(
0
));
private
static
void
addFieldInitAttr
(
MethodNode
mth
,
FieldNode
field
,
IndexInsnNode
putInsn
)
{
InsnNode
assignInsn
;
InsnArg
fldArg
=
putInsn
.
getArg
(
0
);
if
(
fldArg
.
isInsnWrap
())
{
assignInsn
=
((
InsnWrapArg
)
fldArg
).
getWrapInsn
();
}
else
{
assignInsn
=
InsnNode
.
wrapArg
(
fldArg
);
}
field
.
addAttr
(
new
FieldInitInsnAttr
(
mth
,
assignInsn
));
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/ProcessAnonymous.java
浏览文件 @
157e702f
...
...
@@ -10,9 +10,11 @@ import java.util.Set;
import
org.jetbrains.annotations.Nullable
;
import
jadx.api.plugins.input.data.AccessFlags
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.AnonymousClassAttr
;
import
jadx.core.dex.attributes.nodes.AnonymousClassAttr.InlineType
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.ClassNode
;
...
...
@@ -30,6 +32,7 @@ import jadx.core.utils.exceptions.JadxException;
UsageInfoVisitor
.
class
}
)
@SuppressWarnings
(
"BooleanMethodIsAlwaysInverted"
)
public
class
ProcessAnonymous
extends
AbstractVisitor
{
private
boolean
inlineAnonymousClasses
;
...
...
@@ -64,17 +67,26 @@ public class ProcessAnonymous extends AbstractVisitor {
if
(!
canBeAnonymous
(
cls
))
{
return
;
}
MethodNode
anonymousConstructor
=
checkUsage
(
cls
);
MethodNode
anonymousConstructor
=
ListUtils
.
filterOnlyOne
(
cls
.
getMethods
(),
MethodNode:
:
isConstructor
);
if
(
anonymousConstructor
==
null
)
{
return
;
}
InlineType
inlineType
=
checkUsage
(
cls
,
anonymousConstructor
);
if
(
inlineType
==
null
)
{
return
;
}
ArgType
baseType
=
getBaseType
(
cls
);
if
(
baseType
==
null
)
{
return
;
}
ClassNode
outerCls
=
anonymousConstructor
.
getUseIn
().
get
(
0
).
getParentClass
();
ClassNode
outerCls
;
if
(
inlineType
==
InlineType
.
INSTANCE_FIELD
)
{
outerCls
=
cls
.
getUseInMth
().
get
(
0
).
getParentClass
();
}
else
{
outerCls
=
anonymousConstructor
.
getUseIn
().
get
(
0
).
getParentClass
();
}
outerCls
.
addInlinedClass
(
cls
);
cls
.
addAttr
(
new
AnonymousClassAttr
(
outerCls
,
baseType
));
cls
.
addAttr
(
new
AnonymousClassAttr
(
outerCls
,
baseType
,
inlineType
));
cls
.
add
(
AFlag
.
DONT_GENERATE
);
anonymousConstructor
.
add
(
AFlag
.
ANONYMOUS_CONSTRUCTOR
);
...
...
@@ -202,14 +214,11 @@ public class ProcessAnonymous extends AbstractVisitor {
* Checks:
* - class have only one constructor which used only once (allow common code for field init)
* - methods or fields not used outside (allow only nested inner classes with synthetic usage)
* - if constructor used only in class init check if possible inline by instance field
*
* @return
anonymous constructor method
* @return
decided inline type
*/
private
static
MethodNode
checkUsage
(
ClassNode
cls
)
{
MethodNode
ctr
=
ListUtils
.
filterOnlyOne
(
cls
.
getMethods
(),
MethodNode:
:
isConstructor
);
if
(
ctr
==
null
)
{
return
null
;
}
private
static
InlineType
checkUsage
(
ClassNode
cls
,
MethodNode
ctr
)
{
if
(
ctr
.
getUseIn
().
size
()
!=
1
)
{
// check if used in common field init in all constructors
if
(!
checkForCommonFieldInit
(
ctr
))
{
...
...
@@ -219,6 +228,9 @@ public class ProcessAnonymous extends AbstractVisitor {
MethodNode
ctrUseMth
=
ctr
.
getUseIn
().
get
(
0
);
ClassNode
ctrUseCls
=
ctrUseMth
.
getParentClass
();
if
(
ctrUseCls
.
equals
(
cls
))
{
if
(
checkForInstanceFieldUsage
(
cls
,
ctr
))
{
return
InlineType
.
INSTANCE_FIELD
;
}
// exclude self usage
return
null
;
}
...
...
@@ -226,6 +238,20 @@ public class ProcessAnonymous extends AbstractVisitor {
// exclude usage inside inner classes
return
null
;
}
if
(!
checkMethodsUsage
(
cls
,
ctr
,
ctrUseMth
))
{
return
null
;
}
for
(
FieldNode
field
:
cls
.
getFields
())
{
for
(
MethodNode
useMth
:
field
.
getUseIn
())
{
if
(
badMethodUsage
(
cls
,
useMth
,
field
.
getAccessFlags
()))
{
return
null
;
}
}
}
return
InlineType
.
CONSTRUCTOR
;
}
private
static
boolean
checkMethodsUsage
(
ClassNode
cls
,
MethodNode
ctr
,
MethodNode
ctrUseMth
)
{
for
(
MethodNode
mth
:
cls
.
getMethods
())
{
if
(
mth
==
ctr
)
{
continue
;
...
...
@@ -235,18 +261,46 @@ public class ProcessAnonymous extends AbstractVisitor {
continue
;
}
if
(
badMethodUsage
(
cls
,
useMth
,
mth
.
getAccessFlags
()))
{
return
null
;
return
false
;
}
}
}
return
true
;
}
private
static
boolean
checkForInstanceFieldUsage
(
ClassNode
cls
,
MethodNode
ctr
)
{
MethodNode
ctrUseMth
=
ctr
.
getUseIn
().
get
(
0
);
if
(!
ctrUseMth
.
getMethodInfo
().
isClassInit
())
{
return
false
;
}
FieldNode
instFld
=
ListUtils
.
filterOnlyOne
(
cls
.
getFields
(),
f
->
f
.
getAccessFlags
().
containsFlags
(
AccessFlags
.
PUBLIC
,
AccessFlags
.
STATIC
,
AccessFlags
.
FINAL
)
&&
f
.
getFieldInfo
().
getType
().
equals
(
cls
.
getClassInfo
().
getType
()));
if
(
instFld
==
null
)
{
return
false
;
}
List
<
MethodNode
>
instFldUseIn
=
instFld
.
getUseIn
();
if
(
instFldUseIn
.
size
()
!=
2
||
!
instFldUseIn
.
contains
(
ctrUseMth
)
// initialized in class init
||
!
instFldUseIn
.
containsAll
(
cls
.
getUseInMth
())
// class used only with this field
)
{
return
false
;
}
if
(!
checkMethodsUsage
(
cls
,
ctr
,
ctrUseMth
))
{
return
false
;
}
for
(
FieldNode
field
:
cls
.
getFields
())
{
if
(
field
==
instFld
)
{
continue
;
}
for
(
MethodNode
useMth
:
field
.
getUseIn
())
{
if
(
badMethodUsage
(
cls
,
useMth
,
field
.
getAccessFlags
()))
{
return
null
;
return
false
;
}
}
}
return
ctr
;
instFld
.
add
(
AFlag
.
INLINE_INSTANCE_FIELD
);
return
true
;
}
private
static
boolean
badMethodUsage
(
ClassNode
cls
,
MethodNode
useMth
,
AccessInfo
accessFlags
)
{
...
...
@@ -297,6 +351,13 @@ public class ProcessAnonymous extends AbstractVisitor {
if
(
cls
.
root
().
getClsp
().
isImplements
(
superCls
.
getObject
(),
interfaceType
.
getObject
()))
{
return
superCls
;
}
if
(
cls
.
root
().
getArgs
().
isAllowInlineKotlinLambda
())
{
if
(
superCls
.
getObject
().
equals
(
"kotlin.jvm.internal.Lambda"
))
{
// Inline such class with have different semantic: missing 'arity' property.
// For now, it is unclear how it may affect code execution.
return
interfaceType
;
}
}
return
null
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
浏览文件 @
157e702f
...
...
@@ -325,7 +325,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
ClassNode
ctrCls
=
root
.
resolveClass
(
ctr
.
getClassType
());
if
(
ctrCls
!=
null
&&
ctrCls
.
contains
(
AFlag
.
DONT_GENERATE
))
{
AnonymousClassAttr
baseTypeAttr
=
ctrCls
.
get
(
AType
.
ANONYMOUS_CLASS
);
if
(
baseTypeAttr
!=
null
)
{
if
(
baseTypeAttr
!=
null
&&
baseTypeAttr
.
getInlineType
()
==
AnonymousClassAttr
.
InlineType
.
CONSTRUCTOR
)
{
return
baseTypeAttr
.
getBaseType
();
}
}
...
...
jadx-core/src/test/java/jadx/tests/integration/inline/TestInstanceLambda.java
浏览文件 @
157e702f
...
...
@@ -3,12 +3,13 @@ package jadx.tests.integration.inline;
import
java.util.List
;
import
java.util.Map
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
import
org.junit.jupiter.api.Test
;
import
jadx.
NotYetImplemented
;
import
jadx.
core.dex.attributes.AFlag
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.visitors.ProcessAnonymous
;
import
jadx.core.utils.ListUtils
;
import
jadx.tests.api.SmaliTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
...
...
@@ -19,14 +20,17 @@ public class TestInstanceLambda extends SmaliTest {
public
static
class
TestCls
{
public
<
T
>
Map
<
T
,
T
>
test
(
List
<?
extends
T
>
list
)
{
return
toMap
(
list
,
Lambda
.
INSTANCE
);
return
toMap
(
list
,
Lambda
$
1
.
INSTANCE
);
}
/**
* Smali test missing 'T' definition in 'Lambda<T>'
* Note: use '$1' so class looks like generated by compiler and pass check in
* {@link ProcessAnonymous#canBeAnonymous(ClassNode)}
*/
private
static
class
Lambda
<
T
>
implements
Function
<
T
,
T
>
{
public
static
final
Lambda
INSTANCE
=
new
Lambda
();
@SuppressWarnings
({
"CheckStyle"
,
"checkstyle:TypeName"
})
private
static
class
Lambda
$
1
<
T
>
implements
Function
<
T
,
T
>
{
public
static
final
Lambda
$
1
INSTANCE
=
new
Lambda
$
1
();
@Override
public
T
apply
(
T
t
)
{
...
...
@@ -35,12 +39,13 @@ public class TestInstanceLambda extends SmaliTest {
}
private
static
<
T
>
Map
<
T
,
T
>
toMap
(
List
<?
extends
T
>
list
,
Function
<
T
,
T
>
valueMap
)
{
return
list
.
stream
().
collect
(
Collectors
.
toMap
(
k
->
k
,
valueMap
))
;
return
null
;
}
}
@Test
public
void
test
()
{
useJavaInput
();
noDebugInfo
();
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
();
...
...
@@ -50,23 +55,23 @@ public class TestInstanceLambda extends SmaliTest {
public
void
testSmaliDisableInline
()
{
args
.
setInlineAnonymousClasses
(
false
);
List
<
ClassNode
>
classNodes
=
loadFromSmaliFiles
();
assertThat
(
searchTestCls
(
classNodes
,
"Lambda"
))
assertThat
(
searchTestCls
(
classNodes
,
"Lambda
$1
"
))
.
code
()
.
containsOne
(
"class Lambda<T> implements Function<T, T> {"
);
.
containsOne
(
"class Lambda
$1
<T> implements Function<T, T> {"
);
assertThat
(
searchTestCls
(
classNodes
,
"TestCls"
))
.
code
()
.
containsOne
(
"Lambda.INSTANCE"
);
.
containsOne
(
"Lambda
$1
.INSTANCE"
);
}
@NotYetImplemented
(
"Inline lambda by instance field"
)
@Test
public
void
testSmali
()
{
List
<
ClassNode
>
classNodes
=
loadFromSmaliFiles
();
assertThat
(
classNodes
)
assertThat
(
ListUtils
.
filter
(
classNodes
,
c
->
!
c
.
contains
(
AFlag
.
DONT_GENERATE
))
)
.
describedAs
(
"Expect lambda to be inlined"
)
.
hasSize
(
1
);
assertThat
(
searchTestCls
(
classNodes
,
"TestCls"
))
.
code
()
.
doesNotContain
(
"Lambda.INSTANCE"
);
.
doesNotContain
(
"Lambda$1.INSTANCE"
)
.
containsOne
(
"toMap(list, new Function<T, T>() {"
);
}
}
jadx-core/src/test/smali/inline/TestInstanceLambda/Lambda.smali
浏览文件 @
157e702f
.class public Linline/Lambda;
.class public Linline/Lambda
$1
;
.super Ljava/lang/Object;
.implements Ljava/util/function/Function;
...
...
@@ -12,13 +12,13 @@
}
.end annotation
.field public static final INSTANCE:Linline/Lambda;
.field public static final INSTANCE:Linline/Lambda
$1
;
.method static constructor <clinit>()V
.registers 1
new-instance v0, Linline/Lambda;
invoke-direct {v0}, Linline/Lambda;-><init>()V
sput-object v0, Linline/Lambda
;->INSTANCE:Linline/Lambda
;
new-instance v0, Linline/Lambda
$1
;
invoke-direct {v0}, Linline/Lambda
$1
;-><init>()V
sput-object v0, Linline/Lambda
$1;->INSTANCE:Linline/Lambda$1
;
return-void
.end method
...
...
jadx-core/src/test/smali/inline/TestInstanceLambda/TestCls.smali
浏览文件 @
157e702f
...
...
@@ -15,18 +15,12 @@
}
.end annotation
sget-object v0, Linline/Lambda
;->INSTANCE:Linline/Lambda
;
sget-object v0, Linline/Lambda
$1;->INSTANCE:Linline/Lambda$1
;
invoke-static {p1, v0}, Linline/TestCls;->toMap(Ljava/util/List;Ljava/util/function/Function;)Ljava/util/Map;
move-result-object v0
return-object v0
.end method
.method private static synthetic lambda$toMap$0(Ljava/lang/Object;)Ljava/lang/Object;
.registers 1
return-object p0
.end method
.method private static toMap(Ljava/util/List;Ljava/util/function/Function;)Ljava/util/Map;
.registers 4
.annotation system Ldalvik/annotation/Signature;
...
...
@@ -43,14 +37,6 @@
}
.end annotation
invoke-interface {p0}, Ljava/util/List;->stream()Ljava/util/stream/Stream;
move-result-object v0
invoke-custom {}, call_site_0("apply", ()Ljava/util/function/Function;, (Ljava/lang/Object;)Ljava/lang/Object;, invoke-static@Linline/TestCls;->lambda$toMap$0(Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Object;)Ljava/lang/Object;)@Ljava/lang/invoke/LambdaMetafactory;->metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
move-result-object v1
invoke-static {v1, p1}, Ljava/util/stream/Collectors;->toMap(Ljava/util/function/Function;Ljava/util/function/Function;)Ljava/util/stream/Collector;
move-result-object v1
invoke-interface {v0, v1}, Ljava/util/stream/Stream;->collect(Ljava/util/stream/Collector;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Ljava/util/Map;
const/4 v0, 0x0
return-object v0
.end method
jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
浏览文件 @
157e702f
...
...
@@ -401,6 +401,10 @@ public class JadxSettings extends JadxCLIArgs {
this
.
inlineMethods
=
inlineMethods
;
}
public
void
setAllowInlineKotlinLambda
(
boolean
allowInlineKotlinLambda
)
{
this
.
allowInlineKotlinLambda
=
allowInlineKotlinLambda
;
}
public
void
setExtractFinally
(
boolean
extractFinally
)
{
this
.
extractFinally
=
extractFinally
;
}
...
...
jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
浏览文件 @
157e702f
...
...
@@ -538,6 +538,13 @@ public class JadxSettingsWindow extends JDialog {
needReload
();
});
JCheckBox
inlineKotlinLambdas
=
new
JCheckBox
();
inlineKotlinLambdas
.
setSelected
(
settings
.
isAllowInlineKotlinLambda
());
inlineKotlinLambdas
.
addItemListener
(
e
->
{
settings
.
setAllowInlineKotlinLambda
(
e
.
getStateChange
()
==
ItemEvent
.
SELECTED
);
needReload
();
});
JCheckBox
extractFinally
=
new
JCheckBox
();
extractFinally
.
setSelected
(
settings
.
isExtractFinally
());
extractFinally
.
addItemListener
(
e
->
{
...
...
@@ -581,6 +588,7 @@ public class JadxSettingsWindow extends JDialog {
other
.
addRow
(
NLS
.
str
(
"preferences.useDebugInfo"
),
useDebugInfo
);
other
.
addRow
(
NLS
.
str
(
"preferences.inlineAnonymous"
),
inlineAnonymous
);
other
.
addRow
(
NLS
.
str
(
"preferences.inlineMethods"
),
inlineMethods
);
other
.
addRow
(
NLS
.
str
(
"preferences.inlineKotlinLambdas"
),
inlineKotlinLambdas
);
other
.
addRow
(
NLS
.
str
(
"preferences.extractFinally"
),
extractFinally
);
other
.
addRow
(
NLS
.
str
(
"preferences.fsCaseSensitive"
),
fsCaseSensitive
);
other
.
addRow
(
NLS
.
str
(
"preferences.useDx"
),
useDx
);
...
...
jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=Import statements generieren
preferences.useDebugInfo
=
Debug-Infos verwenden
preferences.inlineAnonymous
=
Anonyme Inline-Klassen
preferences.inlineMethods
=
Inline-Methoden
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
#preferences.extractFinally=Extract finally block
preferences.fsCaseSensitive
=
Dateisystem unterscheidet zwischen Groß/Kleinschreibung
preferences.skipResourcesDecode
=
Keine Ressourcen dekodieren
...
...
jadx-gui/src/main/resources/i18n/Messages_en_US.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=Use import statements
preferences.useDebugInfo
=
Use debug info
preferences.inlineAnonymous
=
Inline anonymous classes
preferences.inlineMethods
=
Inline methods
preferences.inlineKotlinLambdas
=
Allow to inline Kotlin Lambdas
preferences.extractFinally
=
Extract finally block
preferences.fsCaseSensitive
=
File system is case-sensitive
preferences.skipResourcesDecode
=
Don't decode resources
...
...
jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.replaceConsts=Reemplazar constantes
#preferences.useDebugInfo=Use debug info
#preferences.inlineAnonymous=
#preferences.inlineMethods=Inline methods
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
#preferences.extractFinally=Extract finally block
#preferences.fsCaseSensitive=
preferences.skipResourcesDecode
=
No descodificar recursos
...
...
jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=import 문 사용
preferences.useDebugInfo
=
디버그 정보 사용
preferences.inlineAnonymous
=
인라인 익명 클래스
preferences.inlineMethods
=
인라인 메서드
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
preferences.extractFinally
=
finally 블록 추출
preferences.fsCaseSensitive
=
파일 시스템 대소문자 구별
preferences.skipResourcesDecode
=
리소스 디코딩 하지 않기
...
...
jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=Utilizar declaração de imports
preferences.useDebugInfo
=
Utilizar informação de depuração
preferences.inlineAnonymous
=
Classes anônimas de uma linha
preferences.inlineMethods
=
Métodos de uma linha
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
preferences.extractFinally
=
Extrair blocos finally
preferences.fsCaseSensitive
=
Sistema de arquivo diferencia maiúsculas de minúsculas
preferences.skipResourcesDecode
=
Não decodificar recursos
...
...
jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=Использовать импорты
preferences.useDebugInfo
=
Отладочная информация
preferences.inlineAnonymous
=
Объединять анонимные классы
preferences.inlineMethods
=
Объединять методы
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
preferences.extractFinally
=
Вычленять finally блоки
preferences.fsCaseSensitive
=
Учитывать регистр в файловой системе
preferences.skipResourcesDecode
=
Не декодировать ресурсы
...
...
jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=使用 import 语句
preferences.useDebugInfo
=
启用调试信息
preferences.inlineAnonymous
=
内联匿名类
preferences.inlineMethods
=
内联方法
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
preferences.extractFinally
=
提取finally块
preferences.fsCaseSensitive
=
文件系统区分大小写
preferences.skipResourcesDecode
=
不反编译资源文件
...
...
jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties
浏览文件 @
157e702f
...
...
@@ -158,6 +158,7 @@ preferences.useImports=使用 import 陳述式
preferences.useDebugInfo
=
使用除錯資訊
preferences.inlineAnonymous
=
內嵌匿名類別
preferences.inlineMethods
=
內嵌方式
#preferences.inlineKotlinLambdas=Allow to inline Kotlin Lambdas
preferences.extractFinally
=
擷取 finally 區塊
preferences.fsCaseSensitive
=
檔案系統區分大小寫
preferences.skipResourcesDecode
=
不要為資源解碼
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录