Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
keyescgm
jadx
提交
17f99ed9
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,发现更多精彩内容 >>
未验证
提交
17f99ed9
编写于
11月 10, 2021
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: adjust class processing order for correct methods inline (#1264)
上级
954d239b
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
292 addition
and
12 deletion
+292
-12
jadx-core/src/main/java/jadx/core/ProcessClass.java
jadx-core/src/main/java/jadx/core/ProcessClass.java
+20
-1
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
+28
-0
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java
...java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java
+1
-7
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
+4
-0
jadx-core/src/main/java/jadx/core/dex/nodes/ProcessState.java
...-core/src/main/java/jadx/core/dex/nodes/ProcessState.java
+4
-0
jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java
...e/src/main/java/jadx/core/dex/visitors/ClassModifier.java
+0
-3
jadx-core/src/main/java/jadx/core/dex/visitors/InlineMethods.java
...e/src/main/java/jadx/core/dex/visitors/InlineMethods.java
+43
-0
jadx-core/src/main/java/jadx/core/dex/visitors/OverrideMethodVisitor.java
...in/java/jadx/core/dex/visitors/OverrideMethodVisitor.java
+1
-1
jadx-core/src/main/java/jadx/core/utils/ListUtils.java
jadx-core/src/main/java/jadx/core/utils/ListUtils.java
+16
-0
jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
+4
-0
jadx-core/src/test/java/jadx/tests/integration/inline/TestSyntheticInline3.java
...a/jadx/tests/integration/inline/TestSyntheticInline3.java
+49
-0
jadx-core/src/test/smali/inline/TestSyntheticInline3/KotlinFunction1.smali
...t/smali/inline/TestSyntheticInline3/KotlinFunction1.smali
+26
-0
jadx-core/src/test/smali/inline/TestSyntheticInline3/TestSyntheticInline3$onCreate$1.smali
...estSyntheticInline3/TestSyntheticInline3$onCreate$1.smali
+63
-0
jadx-core/src/test/smali/inline/TestSyntheticInline3/TestSyntheticInline3.smali
...li/inline/TestSyntheticInline3/TestSyntheticInline3.smali
+33
-0
未找到文件。
jadx-core/src/main/java/jadx/core/ProcessClass.java
浏览文件 @
17f99ed9
package
jadx.core
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
...
...
@@ -85,8 +90,22 @@ public final class ProcessClass {
return
generateCode
(
topParentClass
);
}
try
{
Set
<
ClassNode
>
useIn
=
new
HashSet
<>(
cls
.
getUseIn
());
List
<
ClassNode
>
usedInDeps
=
new
ArrayList
<>();
for
(
ClassNode
depCls
:
cls
.
getDependencies
())
{
process
(
depCls
,
false
);
if
(
useIn
.
contains
(
depCls
))
{
// postpone to resolve cross dependencies
usedInDeps
.
add
(
depCls
);
}
else
{
process
(
depCls
,
false
);
}
}
if
(!
usedInDeps
.
isEmpty
())
{
// process current class before its usage
process
(
cls
,
false
);
for
(
ClassNode
depCls
:
usedInDeps
)
{
process
(
depCls
,
false
);
}
}
ICodeInfo
code
=
process
(
cls
,
true
);
if
(
code
==
null
)
{
...
...
jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
浏览文件 @
17f99ed9
...
...
@@ -9,6 +9,7 @@ import java.util.Iterator;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
org.jetbrains.annotations.NotNull
;
...
...
@@ -29,6 +30,7 @@ import jadx.core.dex.attributes.FieldInitInsnAttr;
import
jadx.core.dex.attributes.nodes.EnumClassAttr
;
import
jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
import
jadx.core.dex.attributes.nodes.MethodInlineAttr
;
import
jadx.core.dex.attributes.nodes.SkipMethodArgsAttr
;
import
jadx.core.dex.info.AccessInfo
;
import
jadx.core.dex.info.ClassInfo
;
...
...
@@ -291,6 +293,9 @@ public class ClassGen {
}
private
void
addMethod
(
ICodeWriter
code
,
MethodNode
mth
)
{
if
(
skipMethod
(
mth
))
{
return
;
}
if
(
code
.
getLength
()
!=
clsDeclOffset
)
{
code
.
newLine
();
}
...
...
@@ -307,6 +312,29 @@ public class ClassGen {
}
}
/**
* Additional checks for inlined methods
*/
private
boolean
skipMethod
(
MethodNode
mth
)
{
MethodInlineAttr
inlineAttr
=
mth
.
get
(
AType
.
METHOD_INLINE
);
if
(
inlineAttr
==
null
||
inlineAttr
.
notNeeded
())
{
return
false
;
}
if
(
mth
.
getUseIn
().
isEmpty
())
{
mth
.
add
(
AFlag
.
DONT_GENERATE
);
return
true
;
}
List
<
MethodNode
>
useInCompleted
=
mth
.
getUseIn
().
stream
()
.
filter
(
m
->
m
.
getTopParentClass
().
getState
().
isProcessComplete
())
.
collect
(
Collectors
.
toList
());
if
(
useInCompleted
.
isEmpty
())
{
mth
.
add
(
AFlag
.
DONT_GENERATE
);
return
true
;
}
mth
.
addDebugComment
(
"Method not inlined, still used in: "
+
useInCompleted
);
return
false
;
}
private
boolean
isMethodsPresents
()
{
for
(
MethodNode
mth
:
cls
.
getMethods
())
{
if
(!
mth
.
contains
(
AFlag
.
DONT_GENERATE
))
{
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java
浏览文件 @
17f99ed9
...
...
@@ -4,8 +4,6 @@ import java.util.List;
import
java.util.Objects
;
import
jadx.api.plugins.input.data.attributes.PinnedAttribute
;
import
jadx.core.Consts
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.InsnNode
;
...
...
@@ -26,11 +24,7 @@ public class MethodInlineAttr extends PinnedAttribute {
}
MethodInlineAttr
mia
=
new
MethodInlineAttr
(
replaceInsn
,
regNums
);
mth
.
addAttr
(
mia
);
if
(
Consts
.
DEBUG
)
{
mth
.
addDebugComment
(
"Removed for inline"
);
}
else
{
mth
.
add
(
AFlag
.
DONT_GENERATE
);
}
mth
.
addDebugComment
(
"Marked for inline"
);
return
mia
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
浏览文件 @
17f99ed9
...
...
@@ -289,6 +289,10 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
return
parentClass
;
}
public
ClassNode
getTopParentClass
()
{
return
parentClass
.
getTopParentClass
();
}
public
boolean
isNoCode
()
{
return
noCode
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ProcessState.java
浏览文件 @
17f99ed9
...
...
@@ -6,4 +6,8 @@ public enum ProcessState {
PROCESS_STARTED
,
PROCESS_COMPLETE
,
GENERATED_AND_UNLOADED
;
public
boolean
isProcessComplete
()
{
return
this
==
PROCESS_COMPLETE
||
this
==
GENERATED_AND_UNLOADED
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java
浏览文件 @
17f99ed9
...
...
@@ -70,9 +70,6 @@ public class ClassModifier extends AbstractVisitor {
* Remove synthetic fields if type is outer class or class will be inlined (anonymous)
*/
private
static
void
removeSyntheticFields
(
ClassNode
cls
)
{
if
(
cls
.
getAccessFlags
().
isStatic
())
{
return
;
}
boolean
inline
=
cls
.
isAnonymous
();
if
(
inline
||
cls
.
getClassInfo
().
isInner
())
{
for
(
FieldNode
field
:
cls
.
getFields
())
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/InlineMethods.java
浏览文件 @
17f99ed9
...
...
@@ -9,6 +9,10 @@ import org.slf4j.LoggerFactory;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.nodes.MethodInlineAttr
;
import
jadx.core.dex.info.FieldInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.BaseInvokeNode
;
import
jadx.core.dex.instructions.IndexInsnNode
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.InvokeNode
;
import
jadx.core.dex.instructions.args.ArgType
;
...
...
@@ -16,11 +20,14 @@ import jadx.core.dex.instructions.args.InsnArg;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.args.SSAVar
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.IMethodDetails
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.visitors.typeinference.TypeInferenceVisitor
;
import
jadx.core.utils.BlockUtils
;
import
jadx.core.utils.ListUtils
;
import
jadx.core.utils.exceptions.JadxException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
...
...
@@ -112,6 +119,7 @@ public class InlineMethods extends AbstractVisitor {
if
(
methodDetailsAttr
!=
null
)
{
inlCopy
.
addAttr
(
methodDetailsAttr
);
}
updateUsageInfo
(
mth
,
callMth
,
mia
.
getInsn
());
}
private
boolean
isAssignNeeded
(
InsnNode
inlineInsn
,
InvokeNode
parentInsn
,
MethodNode
callMthNode
)
{
...
...
@@ -135,4 +143,39 @@ public class InlineMethods extends AbstractVisitor {
ssaVar
.
setType
(
varType
);
return
fakeArg
;
}
private
void
updateUsageInfo
(
MethodNode
mth
,
MethodNode
inlinedMth
,
InsnNode
insn
)
{
inlinedMth
.
getUseIn
().
remove
(
mth
);
insn
.
visitInsns
(
innerInsn
->
{
// TODO: share code with UsageInfoVisitor
switch
(
innerInsn
.
getType
())
{
case
INVOKE:
case
CONSTRUCTOR:
MethodInfo
callMth
=
((
BaseInvokeNode
)
innerInsn
).
getCallMth
();
MethodNode
callMthNode
=
mth
.
root
().
resolveMethod
(
callMth
);
if
(
callMthNode
!=
null
)
{
callMthNode
.
setUseIn
(
ListUtils
.
safeReplace
(
callMthNode
.
getUseIn
(),
inlinedMth
,
mth
));
replaceClsUsage
(
mth
,
inlinedMth
,
callMthNode
.
getParentClass
());
}
break
;
case
IGET:
case
IPUT:
case
SPUT:
case
SGET:
FieldInfo
fieldInfo
=
(
FieldInfo
)
((
IndexInsnNode
)
innerInsn
).
getIndex
();
FieldNode
fieldNode
=
mth
.
root
().
resolveField
(
fieldInfo
);
if
(
fieldNode
!=
null
)
{
fieldNode
.
setUseIn
(
ListUtils
.
safeReplace
(
fieldNode
.
getUseIn
(),
inlinedMth
,
mth
));
replaceClsUsage
(
mth
,
inlinedMth
,
fieldNode
.
getParentClass
());
}
break
;
}
});
}
private
void
replaceClsUsage
(
MethodNode
mth
,
MethodNode
inlinedMth
,
ClassNode
parentClass
)
{
parentClass
.
setUseInMth
(
ListUtils
.
safeReplace
(
parentClass
.
getUseInMth
(),
inlinedMth
,
mth
));
parentClass
.
setUseIn
(
ListUtils
.
safeReplace
(
parentClass
.
getUseIn
(),
inlinedMth
.
getParentClass
(),
mth
.
getParentClass
()));
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/OverrideMethodVisitor.java
浏览文件 @
17f99ed9
...
...
@@ -261,7 +261,7 @@ public class OverrideMethodVisitor extends AbstractVisitor {
}
boolean
updated
=
updateReturnType
(
mth
,
baseMth
,
superTypes
);
if
(
updated
)
{
mth
.
add
Info
Comment
(
"Return type fixed from '"
+
returnType
+
"' to match base method"
);
mth
.
add
Debug
Comment
(
"Return type fixed from '"
+
returnType
+
"' to match base method"
);
}
return
updated
;
}
...
...
jadx-core/src/main/java/jadx/core/utils/ListUtils.java
浏览文件 @
17f99ed9
...
...
@@ -50,4 +50,20 @@ public class ListUtils {
public
static
List
<
BlockNode
>
distinctList
(
List
<
BlockNode
>
list
)
{
return
new
ArrayList
<>(
new
LinkedHashSet
<>(
list
));
}
/**
* Replace old element to new one.
* Support null and empty immutable list (created by Collections.emptyList())
*/
public
static
<
T
>
List
<
T
>
safeReplace
(
List
<
T
>
list
,
T
oldObj
,
T
newObj
)
{
if
(
list
==
null
||
list
.
isEmpty
())
{
// immutable empty list
List
<
T
>
newList
=
new
ArrayList
<>(
1
);
newList
.
add
(
newObj
);
return
newList
;
}
list
.
remove
(
oldObj
);
list
.
add
(
newObj
);
return
list
;
}
}
jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
浏览文件 @
17f99ed9
...
...
@@ -60,6 +60,10 @@ public abstract class SmaliTest extends IntegrationTest {
return
searchCls
(
loadFromSmaliFiles
(),
getTestPkg
()
+
'.'
+
clsName
);
}
protected
ClassNode
getClassNodeFromSmaliFiles
()
{
return
searchCls
(
loadFromSmaliFiles
(),
getTestPkg
()
+
'.'
+
getTestName
());
}
protected
List
<
ClassNode
>
loadFromSmaliFiles
()
{
jadxDecompiler
=
loadFiles
(
collectSmaliFiles
(
getTestPkg
(),
getTestName
()));
RootNode
root
=
JadxInternalAccess
.
getRoot
(
jadxDecompiler
);
...
...
jadx-core/src/test/java/jadx/tests/integration/inline/TestSyntheticInline3.java
0 → 100644
浏览文件 @
17f99ed9
package
jadx.tests.integration.inline
;
import
java.util.function.Function
;
import
org.junit.jupiter.api.Test
;
import
jadx.tests.api.SmaliTest
;
import
static
jadx
.
tests
.
api
.
utils
.
assertj
.
JadxAssertions
.
assertThat
;
public
class
TestSyntheticInline3
extends
SmaliTest
{
@SuppressWarnings
({
"Convert2Lambda"
,
"TrivialFunctionalExpressionUsage"
})
public
static
class
TestCls
{
private
String
strField
;
private
String
str
()
{
return
"a"
;
}
private
void
test
()
{
new
Function
<
String
,
Void
>()
{
@Override
public
Void
apply
(
String
s
)
{
System
.
out
.
println
(
s
+
strField
+
str
());
return
null
;
}
}.
apply
(
"c"
);
}
}
@Test
public
void
test
()
{
assertThat
(
getClassNode
(
TestCls
.
class
))
.
code
();
}
@Test
public
void
testSmali
()
{
allowWarnInCode
();
disableCompilation
();
assertThat
(
getClassNodeFromSmaliFiles
())
.
code
()
.
doesNotContain
(
".access$getDialog$p("
)
.
doesNotContain
(
".access$getChooserIntent("
)
.
doesNotContain
(
"= r1;"
)
.
doesNotContain
(
"this$0"
);
}
}
jadx-core/src/test/smali/inline/TestSyntheticInline3/KotlinFunction1.smali
0 → 100644
浏览文件 @
17f99ed9
.class public interface abstract Lkotlin/jvm/functions/Function1;
.super Ljava/lang/Object;
.source "SourceFile"
.implements Lkotlin/Function;
.annotation system Ldalvik/annotation/Signature;
value = {
"<P1:",
"Ljava/lang/Object;",
"R:",
"Ljava/lang/Object;",
">",
"Ljava/lang/Object;",
"Lkotlin/Function<",
"TR;>;"
}
.end annotation
.method public abstract invoke(Ljava/lang/Object;)Ljava/lang/Object;
.annotation system Ldalvik/annotation/Signature;
value = {
"(TP1;)TR;"
}
.end annotation
.end method
jadx-core/src/test/smali/inline/TestSyntheticInline3/TestSyntheticInline3$onCreate$1.smali
0 → 100644
浏览文件 @
17f99ed9
.class final Linline/TestSyntheticInline3$onCreate$1;
.super Lkotlin/jvm/internal/Lambda;
.implements Lkotlin/jvm/functions/Function1;
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x18
name = null
.end annotation
.annotation system Ldalvik/annotation/Signature;
value = {
"Lkotlin/jvm/internal/Lambda;",
"Lkotlin/jvm/functions/Function1<",
"Ljava/lang/String;",
"Lkotlin/Unit;",
">;"
}
.end annotation
.field final synthetic this$0:Linline/TestSyntheticInline3;
.method constructor <init>(Linline/TestSyntheticInline3;)V
.registers 2
iput-object p1, p0, Linline/TestSyntheticInline3$onCreate$1;->this$0:Linline/TestSyntheticInline3;
const/4 p1, 0x1
invoke-direct {p0, p1}, Lkotlin/jvm/internal/Lambda;-><init>(I)V
return-void
.end method
.method public bridge synthetic invoke(Ljava/lang/Object;)Ljava/lang/Object;
.registers 2
check-cast p1, Ljava/lang/String;
invoke-virtual {p0, p1}, Linline/TestSyntheticInline3$onCreate$1;->invoke(Ljava/lang/String;)V
sget-object p1, Lkotlin/Unit;->INSTANCE:Lkotlin/Unit;
return-object p1
.end method
.method public final invoke(Ljava/lang/String;)V
.registers 5
iget-object v0, p0, Linline/TestSyntheticInline3$onCreate$1;->this$0:Linline/TestSyntheticInline3;
invoke-static {v0}, Linline/TestSyntheticInline3;->access$getDialog$p(Linline/TestSyntheticInline3;)Landroidx/appcompat/app/AlertDialog;
move-result-object v0
if-nez v0, :cond_9
goto :goto_c
:cond_9
invoke-virtual {v0}, Landroidx/appcompat/app/AppCompatDialog;->dismiss()V
:goto_c
iget-object v0, p0, Linline/TestSyntheticInline3$onCreate$1;->this$0:Linline/TestSyntheticInline3;
invoke-virtual {v0}, Landroid/app/Activity;->getIntent()Landroid/content/Intent;
move-result-object v1
const-string v2, "intent"
invoke-static {v1, v2}, Lkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
invoke-static {v0, v1, p1}, Linline/TestSyntheticInline3;->access$getChooserIntent(Linline/TestSyntheticInline3;Landroid/content/Intent;Ljava/lang/String;)Landroid/content/Intent;
move-result-object p1
invoke-virtual {v0, p1}, Landroid/app/Activity;->startActivity(Landroid/content/Intent;)V
iget-object p1, p0, Linline/TestSyntheticInline3$onCreate$1;->this$0:Linline/TestSyntheticInline3;
invoke-virtual {p1}, Landroid/app/Activity;->finish()V
return-void
.end method
jadx-core/src/test/smali/inline/TestSyntheticInline3/TestSyntheticInline3.smali
0 → 100644
浏览文件 @
17f99ed9
.class public final Linline/TestSyntheticInline3;
.super Landroid/app/Activity;
.field private dialog:Landroidx/appcompat/app/AlertDialog;
.method public static final synthetic access$getChooserIntent(Linline/TestSyntheticInline3;Landroid/content/Intent;Ljava/lang/String;)Landroid/content/Intent;
.registers 3
invoke-direct {p0, p1, p2}, Linline/TestSyntheticInline3;->getChooserIntent(Landroid/content/Intent;Ljava/lang/String;)Landroid/content/Intent;
move-result-object p0
return-object p0
.end method
.method public static final synthetic access$getDialog$p(Linline/TestSyntheticInline3;)Landroidx/appcompat/app/AlertDialog;
.registers 1
iget-object p0, p0, Linline/TestSyntheticInline3;->dialog:Landroidx/appcompat/app/AlertDialog;
return-object p0
.end method
.method protected onCreate(Landroid/os/Bundle;)V
.registers 3
invoke-super {p0, p1}, Landroidx/fragment/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V
new-instance v0, Linline/TestSyntheticInline3$onCreate$1;
invoke-direct {v0, p0}, Linline/TestSyntheticInline3$onCreate$1;-><init>(Linline/TestSyntheticInline3;)V
return-void
.end method
.method private final getChooserIntent(Landroid/content/Intent;Ljava/lang/String;)Landroid/content/Intent;
.registers 5
new-instance v0, Landroid/content/Intent;
invoke-direct {v0, p1}, Landroid/content/Intent;-><init>(Landroid/content/Intent;)V
return-object v0
.end method
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录