Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
2301_76393173
jadx
提交
ab970840
J
jadx
项目概览
2301_76393173
/
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 搜索 >>
提交
ab970840
编写于
7月 25, 2019
作者:
S
Skylot
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor: move passes list to root node
上级
0911b2dc
变更
23
隐藏空白更改
内联
并排
Showing
23 changed file
with
272 addition
and
148 deletion
+272
-148
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
+13
-39
jadx-core/src/main/java/jadx/api/JavaClass.java
jadx-core/src/main/java/jadx/api/JavaClass.java
+3
-4
jadx-core/src/main/java/jadx/core/ProcessClass.java
jadx-core/src/main/java/jadx/core/ProcessClass.java
+46
-16
jadx-core/src/main/java/jadx/core/codegen/CodeGen.java
jadx-core/src/main/java/jadx/core/codegen/CodeGen.java
+18
-18
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
+4
-3
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+6
-1
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+24
-7
jadx-core/src/main/java/jadx/core/dex/nodes/ProcessState.java
...-core/src/main/java/jadx/core/dex/nodes/ProcessState.java
+3
-2
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+20
-1
jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java
.../src/main/java/jadx/core/dex/visitors/DepthTraversal.java
+5
-0
jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
...core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
+1
-0
jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java
jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java
+11
-3
jadx-core/src/main/java/jadx/core/utils/DebugUtils.java
jadx-core/src/main/java/jadx/core/utils/DebugUtils.java
+1
-1
jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java
...n/java/jadx/core/utils/android/AndroidResourcesUtils.java
+1
-1
jadx-core/src/main/java/jadx/core/utils/files/InputFile.java
jadx-core/src/main/java/jadx/core/utils/files/InputFile.java
+4
-4
jadx-core/src/test/java/jadx/api/JadxDecompilerTest.java
jadx-core/src/test/java/jadx/api/JadxDecompilerTest.java
+22
-5
jadx-core/src/test/java/jadx/api/JadxInternalAccess.java
jadx-core/src/test/java/jadx/api/JadxInternalAccess.java
+0
-7
jadx-core/src/test/java/jadx/core/utils/files/InputFileTest.java
...re/src/test/java/jadx/core/utils/files/InputFileTest.java
+2
-2
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
+33
-15
jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java
...e/src/test/java/jadx/tests/external/BaseExternalTest.java
+3
-7
jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java
...va/jadx/tests/integration/debuginfo/TestLineNumbers2.java
+4
-4
jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java
...adx/tests/integration/debuginfo/TestReturnSourceLine.java
+9
-8
jadx-core/src/test/java/jadx/tests/integration/loops/TestComplexWhileLoop.java
...va/jadx/tests/integration/loops/TestComplexWhileLoop.java
+39
-0
未找到文件。
jadx-core/src/main/java/jadx/api/JadxDecompiler.java
浏览文件 @
ab970840
...
...
@@ -27,14 +27,12 @@ import org.slf4j.Logger;
import
org.slf4j.LoggerFactory
;
import
jadx.core.Jadx
;
import
jadx.core.ProcessClass
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.FieldNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.dex.visitors.SaveCode
;
import
jadx.core.export.ExportGradleProject
;
import
jadx.core.utils.Utils
;
...
...
@@ -72,12 +70,9 @@ public final class JadxDecompiler {
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
JadxDecompiler
.
class
);
private
JadxArgs
args
;
private
final
List
<
InputFile
>
inputFiles
=
new
ArrayList
<>();
private
List
<
InputFile
>
inputFiles
;
private
RootNode
root
;
private
List
<
IDexTreeVisitor
>
passes
;
private
List
<
JavaClass
>
classes
;
private
List
<
ResourceFile
>
resources
;
...
...
@@ -98,48 +93,45 @@ public final class JadxDecompiler {
public
void
load
()
{
reset
();
JadxArgsValidator
.
validate
(
args
);
init
();
LOG
.
info
(
"loading ..."
);
loadFiles
(
args
.
getInputFiles
());
inputFiles
=
loadFiles
(
args
.
getInputFiles
());
root
=
new
RootNode
(
args
);
root
.
load
(
inputFiles
);
root
.
initClassPath
();
root
.
loadResources
(
getResources
());
initVisitors
();
}
void
init
()
{
this
.
passes
=
Jadx
.
getPassesList
(
args
);
root
.
initPasses
();
}
void
reset
()
{
private
void
reset
()
{
root
=
null
;
classes
=
null
;
resources
=
null
;
xmlParser
=
null
;
root
=
null
;
passes
=
null
;
classesMap
.
clear
();
methodsMap
.
clear
();
fieldsMap
.
clear
();
}
public
static
String
getVersion
()
{
return
Jadx
.
getVersion
();
}
private
void
loadFiles
(
List
<
File
>
files
)
{
private
List
<
InputFile
>
loadFiles
(
List
<
File
>
files
)
{
if
(
files
.
isEmpty
())
{
throw
new
JadxRuntimeException
(
"Empty file list"
);
}
inputFiles
.
clear
();
List
<
InputFile
>
filesList
=
new
ArrayList
<>
();
for
(
File
file
:
files
)
{
try
{
InputFile
.
addFilesFrom
(
file
,
inputFiles
,
args
.
isSkipSources
());
InputFile
.
addFilesFrom
(
file
,
filesList
,
args
.
isSkipSources
());
}
catch
(
Exception
e
)
{
throw
new
JadxRuntimeException
(
"Error load file: "
+
file
,
e
);
}
}
return
filesList
;
}
public
void
save
()
{
...
...
@@ -299,20 +291,6 @@ public final class JadxDecompiler {
root
.
getErrorsCounter
().
printReport
();
}
private
void
initVisitors
()
{
for
(
IDexTreeVisitor
pass
:
passes
)
{
try
{
pass
.
init
(
root
);
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Visitor init failed: {}"
,
pass
.
getClass
().
getSimpleName
(),
e
);
}
}
}
void
processClass
(
ClassNode
cls
)
{
ProcessClass
.
process
(
cls
,
passes
,
true
);
}
void
generateSmali
(
ClassNode
cls
)
{
Path
path
=
cls
.
dex
().
getDexFile
().
getPath
();
String
className
=
Utils
.
makeQualifiedObjectName
(
cls
.
getClassInfo
().
getType
().
getObject
());
...
...
@@ -341,10 +319,6 @@ public final class JadxDecompiler {
return
root
;
}
List
<
IDexTreeVisitor
>
getPasses
()
{
return
passes
;
}
synchronized
BinaryXMLParser
getXmlParser
()
{
if
(
xmlParser
==
null
)
{
xmlParser
=
new
BinaryXMLParser
(
root
);
...
...
jadx-core/src/main/java/jadx/api/JavaClass.java
浏览文件 @
ab970840
...
...
@@ -9,7 +9,6 @@ import java.util.Map;
import
org.jetbrains.annotations.Nullable
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
import
jadx.core.dex.info.AccessInfo
;
...
...
@@ -43,7 +42,7 @@ public final class JavaClass implements JavaNode {
}
public
String
getCode
()
{
CodeWriter
code
=
cls
.
getCode
();
ICodeInfo
code
=
cls
.
getCode
();
if
(
code
==
null
)
{
decompile
();
code
=
cls
.
getCode
();
...
...
@@ -59,7 +58,7 @@ public final class JavaClass implements JavaNode {
return
;
}
if
(
cls
.
getCode
()
==
null
)
{
decompiler
.
processClass
(
cls
);
cls
.
decompile
(
);
load
();
}
}
...
...
@@ -135,7 +134,7 @@ public final class JavaClass implements JavaNode {
private
Map
<
CodePosition
,
Object
>
getCodeAnnotations
()
{
decompile
();
CodeWriter
code
=
cls
.
getCode
();
ICodeInfo
code
=
cls
.
getCode
();
if
(
code
==
null
)
{
return
Collections
.
emptyMap
();
}
...
...
jadx-core/src/main/java/jadx/core/ProcessClass.java
浏览文件 @
ab970840
package
jadx.core
;
import
java.util.List
;
import
org.jetbrains.annotations.NotNull
;
import
jadx.api.ICodeInfo
;
import
jadx.core.codegen.CodeGen
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.ProcessState
;
import
jadx.core.dex.visitors.DepthTraversal
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.utils.ErrorsCounter
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
LOADED
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
NOT_LOADED
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
PROCESS
ED
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
STARTED
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
PROCESS
_COMPLETE
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
PROCESS_
STARTED
;
public
final
class
ProcessClass
{
private
ProcessClass
()
{
}
public
static
void
process
(
ClassNode
cls
,
List
<
IDexTreeVisitor
>
passes
,
boolean
generateCode
)
{
if
(!
generateCode
&&
cls
.
getState
()
==
PROCESSED
)
{
return
;
public
static
void
process
(
ClassNode
cls
)
{
process
(
cls
,
false
);
}
@NotNull
public
static
ICodeInfo
generateCode
(
ClassNode
cls
)
{
ICodeInfo
codeInfo
=
process
(
cls
,
true
);
if
(
codeInfo
==
null
)
{
throw
new
JadxRuntimeException
(
"Failed to generate code for class: "
+
cls
.
getFullName
());
}
return
codeInfo
;
}
private
static
ICodeInfo
process
(
ClassNode
cls
,
boolean
generateCode
)
{
ClassNode
topParentClass
=
cls
.
getTopParentClass
();
if
(
topParentClass
!=
cls
)
{
return
process
(
topParentClass
,
generateCode
);
}
if
(!
generateCode
&&
cls
.
getState
()
==
PROCESS_COMPLETE
)
{
// nothing to do
return
null
;
}
synchronized
(
getSyncObj
(
cls
))
{
try
{
if
(
cls
.
getState
()
==
NOT_LOADED
)
{
cls
.
load
();
cls
.
setState
(
STARTED
);
for
(
IDexTreeVisitor
visitor
:
passes
)
{
}
if
(
cls
.
getState
()
==
LOADED
)
{
cls
.
setState
(
PROCESS_STARTED
);
for
(
IDexTreeVisitor
visitor
:
cls
.
root
().
getPasses
())
{
DepthTraversal
.
visit
(
visitor
,
cls
);
}
cls
.
setState
(
PROCESS
ED
);
cls
.
setState
(
PROCESS
_COMPLETE
);
}
if
(
cls
.
getState
()
==
PROCESSED
&&
generateCode
)
{
processDependencies
(
cls
,
passes
);
CodeGen
.
generate
(
cls
);
if
(
generateCode
&&
cls
.
getState
()
==
PROCESS_COMPLETE
)
{
processDependencies
(
cls
);
ICodeInfo
code
=
CodeGen
.
generate
(
cls
);
cls
.
setState
(
ProcessState
.
GENERATED
);
// TODO: unload class (need to build dependency tree or allow to load class several times)
return
code
;
}
}
catch
(
Exception
e
)
{
}
catch
(
Throwable
e
)
{
ErrorsCounter
.
classError
(
cls
,
e
.
getClass
().
getSimpleName
(),
e
);
}
}
return
null
;
}
p
ublic
static
Object
getSyncObj
(
ClassNode
cls
)
{
p
rivate
static
Object
getSyncObj
(
ClassNode
cls
)
{
return
cls
.
getClassInfo
();
}
private
static
void
processDependencies
(
ClassNode
cls
,
List
<
IDexTreeVisitor
>
passes
)
{
cls
.
getDependencies
().
forEach
(
depCls
->
process
(
depCls
,
passes
,
false
));
private
static
void
processDependencies
(
ClassNode
cls
)
{
for
(
ClassNode
depCls
:
cls
.
getDependencies
())
{
process
(
depCls
,
false
);
}
}
}
jadx-core/src/main/java/jadx/core/codegen/CodeGen.java
浏览文件 @
ab970840
...
...
@@ -2,6 +2,7 @@ package jadx.core.codegen;
import
java.util.concurrent.Callable
;
import
jadx.api.ICodeInfo
;
import
jadx.api.JadxArgs
;
import
jadx.core.codegen.json.JsonCodeGen
;
import
jadx.core.dex.attributes.AFlag
;
...
...
@@ -10,33 +11,32 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
public
class
CodeGen
{
public
static
void
generate
(
ClassNode
cls
)
{
public
static
ICodeInfo
generate
(
ClassNode
cls
)
{
if
(
cls
.
contains
(
AFlag
.
DONT_GENERATE
))
{
cls
.
setCode
(
CodeWriter
.
EMPTY
)
;
}
else
{
JadxArgs
args
=
cls
.
root
().
getArgs
();
switch
(
args
.
getOutputFormat
())
{
case
JAVA:
generateJavaCode
(
cls
,
args
);
break
;
case
JSON:
generateJson
(
cls
);
break
;
}
return
CodeWriter
.
EMPTY
;
}
JadxArgs
args
=
cls
.
root
().
getArgs
();
switch
(
args
.
getOutputFormat
())
{
case
JAVA:
return
generateJavaCode
(
cls
,
args
);
case
JSON:
return
generateJson
(
cls
);
default
:
throw
new
JadxRuntimeException
(
"Unknown output format"
);
}
}
private
static
void
generateJavaCode
(
ClassNode
cls
,
JadxArgs
args
)
{
private
static
ICodeInfo
generateJavaCode
(
ClassNode
cls
,
JadxArgs
args
)
{
ClassGen
clsGen
=
new
ClassGen
(
cls
,
args
);
CodeWriter
code
=
wrapCodeGen
(
cls
,
clsGen:
:
makeClass
);
cls
.
setCode
(
code
);
return
wrapCodeGen
(
cls
,
clsGen:
:
makeClass
);
}
private
static
void
generateJson
(
ClassNode
cls
)
{
private
static
ICodeInfo
generateJson
(
ClassNode
cls
)
{
JsonCodeGen
codeGen
=
new
JsonCodeGen
(
cls
);
String
clsJson
=
wrapCodeGen
(
cls
,
codeGen:
:
process
);
cls
.
setCode
(
new
CodeWriter
(
clsJson
)
);
return
new
CodeWriter
(
clsJson
);
}
private
static
<
R
>
R
wrapCodeGen
(
ClassNode
cls
,
Callable
<
R
>
codeGenFunc
)
{
...
...
jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java
浏览文件 @
ab970840
...
...
@@ -24,8 +24,6 @@ public class CodeWriter implements ICodeInfo {
public
static
final
String
NL
=
System
.
getProperty
(
"line.separator"
);
public
static
final
String
INDENT_STR
=
" "
;
public
static
final
CodeWriter
EMPTY
=
new
CodeWriter
().
finish
();
private
static
final
boolean
ADD_LINE_NUMBERS
=
false
;
private
static
final
String
[]
INDENT_CACHE
=
{
...
...
@@ -37,6 +35,8 @@ public class CodeWriter implements ICodeInfo {
INDENT_STR
+
INDENT_STR
+
INDENT_STR
+
INDENT_STR
+
INDENT_STR
,
};
public
static
final
CodeWriter
EMPTY
=
new
CodeWriter
().
finish
();
private
StringBuilder
buf
;
@Nullable
private
String
code
;
...
...
@@ -53,7 +53,8 @@ public class CodeWriter implements ICodeInfo {
this
.
indent
=
0
;
this
.
indentStr
=
""
;
if
(
ADD_LINE_NUMBERS
)
{
incIndent
(
2
);
incIndent
(
3
);
add
(
indentStr
);
}
}
...
...
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
浏览文件 @
ab970840
...
...
@@ -788,8 +788,13 @@ public class InsnGen {
* Add additional cast for overloaded method argument.
*/
private
boolean
processOverloadedArg
(
CodeWriter
code
,
MethodNode
callMth
,
InsnArg
arg
,
int
origPos
)
{
ArgType
origType
;
List
<
RegisterArg
>
arguments
=
callMth
.
getArguments
(
false
);
if
(
arguments
==
null
||
arguments
.
isEmpty
())
{
// try to load class
callMth
.
getParentClass
().
loadAndProcess
();
arguments
=
callMth
.
getArguments
(
false
);
}
ArgType
origType
;
if
(
arguments
==
null
||
arguments
.
isEmpty
())
{
mth
.
addComment
(
"JADX INFO: used method not loaded: "
+
callMth
+
", types can be incorrect"
);
origType
=
callMth
.
getMethodInfo
().
getArgumentsTypes
().
get
(
origPos
);
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
浏览文件 @
ab970840
...
...
@@ -16,8 +16,9 @@ import com.android.dex.ClassData.Method;
import
com.android.dex.ClassDef
;
import
com.android.dex.Dex
;
import
jadx.api.ICodeInfo
;
import
jadx.core.Consts
;
import
jadx.core.
codegen.CodeWriter
;
import
jadx.core.
ProcessClass
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.annotations.Annotation
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
...
...
@@ -36,6 +37,7 @@ import jadx.core.dex.nodes.parser.StaticValuesParser;
import
jadx.core.utils.exceptions.DecodeException
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
LOADED
;
import
static
jadx
.
core
.
dex
.
nodes
.
ProcessState
.
UNLOADED
;
public
class
ClassNode
extends
LineAttrNode
implements
ILoadable
,
ICodeNode
{
...
...
@@ -53,13 +55,13 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
private
List
<
ClassNode
>
innerClasses
=
new
ArrayList
<>();
// store decompiled code
private
CodeWriter
code
;
private
ICodeInfo
code
;
// store smali
private
String
smali
;
// store parent for inner classes or 'this' otherwise
private
ClassNode
parentClass
;
private
ProcessState
state
=
ProcessState
.
NOT_LOADED
;
private
volatile
ProcessState
state
=
ProcessState
.
NOT_LOADED
;
private
List
<
ClassNode
>
dependencies
=
Collections
.
emptyList
();
// cache maps
...
...
@@ -234,14 +236,28 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
&&
fileName
.
endsWith
(
'$'
+
name
))
{
return
;
}
ClassInfo
parentCl
as
s
=
clsInfo
.
getTopParentClass
();
if
(
parentCl
ass
!=
null
&&
fileName
.
equals
(
parentClas
s
.
getShortName
()))
{
ClassInfo
parentCls
=
clsInfo
.
getTopParentClass
();
if
(
parentCl
s
!=
null
&&
fileName
.
equals
(
parentCl
s
.
getShortName
()))
{
return
;
}
}
this
.
addAttr
(
new
SourceFileAttr
(
fileName
));
}
public
void
loadAndProcess
()
{
ProcessClass
.
process
(
this
);
}
public
ICodeInfo
decompile
()
{
if
(
code
!=
null
)
{
return
code
;
}
ICodeInfo
codeInfo
=
ProcessClass
.
generateCode
(
this
);
// TODO: don't store code in class node
setCode
(
codeInfo
);
return
codeInfo
;
}
@Override
public
void
load
()
{
for
(
MethodNode
mth
:
getMethods
())
{
...
...
@@ -254,6 +270,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
for
(
ClassNode
innerCls
:
getInnerClasses
())
{
innerCls
.
load
();
}
setState
(
LOADED
);
}
@Override
...
...
@@ -471,11 +488,11 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
return
clsInfo
.
getAliasPkg
();
}
public
void
setCode
(
CodeWriter
code
)
{
public
void
setCode
(
ICodeInfo
code
)
{
this
.
code
=
code
;
}
public
CodeWriter
getCode
()
{
public
ICodeInfo
getCode
()
{
return
code
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/ProcessState.java
浏览文件 @
ab970840
...
...
@@ -2,8 +2,9 @@ package jadx.core.dex.nodes;
public
enum
ProcessState
{
NOT_LOADED
,
STARTED
,
PROCESSED
,
LOADED
,
PROCESS_STARTED
,
PROCESS_COMPLETE
,
GENERATED
,
UNLOADED
}
jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
浏览文件 @
ab970840
...
...
@@ -12,6 +12,7 @@ import jadx.api.JadxArgs;
import
jadx.api.ResourceFile
;
import
jadx.api.ResourceType
;
import
jadx.api.ResourcesLoader
;
import
jadx.core.Jadx
;
import
jadx.core.clsp.ClspGraph
;
import
jadx.core.clsp.NMethod
;
import
jadx.core.dex.info.ClassInfo
;
...
...
@@ -20,6 +21,7 @@ import jadx.core.dex.info.FieldInfo;
import
jadx.core.dex.info.InfoStorage
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.dex.visitors.typeinference.TypeUpdate
;
import
jadx.core.utils.CacheStorage
;
import
jadx.core.utils.ErrorsCounter
;
...
...
@@ -35,8 +37,10 @@ import jadx.core.xmlgen.ResourceStorage;
public
class
RootNode
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
RootNode
.
class
);
private
final
ErrorsCounter
errorsCounter
=
new
ErrorsCounter
();
private
final
JadxArgs
args
;
private
final
List
<
IDexTreeVisitor
>
passes
;
private
final
ErrorsCounter
errorsCounter
=
new
ErrorsCounter
();
private
final
StringUtils
stringUtils
;
private
final
ConstStorage
constValues
;
private
final
InfoStorage
infoStorage
=
new
InfoStorage
();
...
...
@@ -52,6 +56,7 @@ public class RootNode {
public
RootNode
(
JadxArgs
args
)
{
this
.
args
=
args
;
this
.
passes
=
Jadx
.
getPassesList
(
args
);
this
.
stringUtils
=
new
StringUtils
(
args
);
this
.
constValues
=
new
ConstStorage
(
args
);
this
.
typeUpdate
=
new
TypeUpdate
(
this
);
...
...
@@ -208,6 +213,20 @@ public class RootNode {
return
cls
.
dex
().
deepResolveField
(
cls
,
field
);
}
public
List
<
IDexTreeVisitor
>
getPasses
()
{
return
passes
;
}
public
void
initPasses
()
{
for
(
IDexTreeVisitor
pass
:
passes
)
{
try
{
pass
.
init
(
this
);
}
catch
(
Exception
e
)
{
LOG
.
error
(
"Visitor init failed: {}"
,
pass
.
getClass
().
getSimpleName
(),
e
);
}
}
}
@Nullable
public
ArgType
getMethodGenericReturnType
(
MethodInfo
callMth
)
{
MethodNode
methodNode
=
deepResolveMethod
(
callMth
);
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java
浏览文件 @
ab970840
...
...
@@ -4,6 +4,7 @@ import jadx.core.dex.attributes.AType;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.utils.ErrorsCounter
;
import
jadx.core.utils.exceptions.JadxOverflowException
;
public
class
DepthTraversal
{
...
...
@@ -13,6 +14,8 @@ public class DepthTraversal {
cls
.
getInnerClasses
().
forEach
(
inCls
->
visit
(
visitor
,
inCls
));
cls
.
getMethods
().
forEach
(
mth
->
visit
(
visitor
,
mth
));
}
}
catch
(
StackOverflowError
e
)
{
ErrorsCounter
.
classError
(
cls
,
"StackOverflow in pass: "
+
visitor
.
getClass
().
getSimpleName
(),
new
JadxOverflowException
(
""
));
}
catch
(
Exception
e
)
{
ErrorsCounter
.
classError
(
cls
,
e
.
getClass
().
getSimpleName
()
+
" in pass: "
+
visitor
.
getClass
().
getSimpleName
(),
e
);
...
...
@@ -25,6 +28,8 @@ public class DepthTraversal {
}
try
{
visitor
.
visit
(
mth
);
}
catch
(
StackOverflowError
e
)
{
ErrorsCounter
.
methodError
(
mth
,
"StackOverflow in pass: "
+
visitor
.
getClass
().
getSimpleName
(),
new
JadxOverflowException
(
""
));
}
catch
(
Exception
e
)
{
ErrorsCounter
.
methodError
(
mth
,
e
.
getClass
().
getSimpleName
()
+
" in pass: "
+
visitor
.
getClass
().
getSimpleName
(),
e
);
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
浏览文件 @
ab970840
...
...
@@ -275,6 +275,7 @@ public class ModVisitor extends AbstractVisitor {
if
(!
mth
.
getParentClass
().
getInnerClasses
().
contains
(
classNode
))
{
return
;
}
classNode
.
loadAndProcess
();
Map
<
InsnArg
,
FieldNode
>
argsMap
=
getArgsToFieldsMapping
(
callMthNode
,
co
);
if
(
argsMap
.
isEmpty
()
&&
!
callMthNode
.
getArguments
(
true
).
isEmpty
())
{
return
;
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java
浏览文件 @
ab970840
...
...
@@ -2,6 +2,7 @@ package jadx.core.dex.visitors;
import
java.io.File
;
import
jadx.api.ICodeInfo
;
import
jadx.api.JadxArgs
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.attributes.AFlag
;
...
...
@@ -17,13 +18,20 @@ public class SaveCode {
if
(
cls
.
contains
(
AFlag
.
DONT_GENERATE
))
{
return
;
}
CodeWriter
clsC
ode
=
cls
.
getCode
();
if
(
c
lsC
ode
==
null
)
{
ICodeInfo
c
ode
=
cls
.
getCode
();
if
(
code
==
null
)
{
throw
new
JadxRuntimeException
(
"Code not generated for class "
+
cls
.
getFullName
());
}
if
(
c
lsC
ode
==
CodeWriter
.
EMPTY
)
{
if
(
code
==
CodeWriter
.
EMPTY
)
{
return
;
}
CodeWriter
clsCode
;
if
(
code
instanceof
CodeWriter
)
{
clsCode
=
(
CodeWriter
)
code
;
}
else
{
// TODO: move 'save' method from CodeWriter
clsCode
=
new
CodeWriter
(
code
.
getCodeStr
());
}
String
fileName
=
cls
.
getClassInfo
().
getAliasFullPath
()
+
getFileExtension
(
cls
);
clsCode
.
save
(
dir
,
fileName
);
}
...
...
jadx-core/src/main/java/jadx/core/utils/DebugUtils.java
浏览文件 @
ab970840
...
...
@@ -140,7 +140,7 @@ public class DebugUtils {
}
}
}
checkPHI
(
mth
);
//
checkPHI(mth);
}
private
static
void
checkSSAVar
(
MethodNode
mth
,
InsnNode
insn
,
RegisterArg
reg
)
{
...
...
jadx-core/src/main/java/jadx/core/utils/android/AndroidResourcesUtils.java
浏览文件 @
ab970840
...
...
@@ -88,7 +88,7 @@ public class AndroidResourcesUtils {
}
ClassNode
rCls
=
new
ClassNode
(
dexNodes
.
get
(
0
),
clsName
,
AccessFlags
.
ACC_PUBLIC
|
AccessFlags
.
ACC_FINAL
);
rCls
.
addAttr
(
AType
.
COMMENTS
,
"This class is generated by JADX"
);
rCls
.
setState
(
ProcessState
.
PROCESS
ED
);
rCls
.
setState
(
ProcessState
.
PROCESS
_COMPLETE
);
return
rCls
;
}
...
...
jadx-core/src/main/java/jadx/core/utils/files/InputFile.java
浏览文件 @
ab970840
...
...
@@ -139,10 +139,10 @@ public class InputFile {
Files
.
copy
(
inputStream
,
jarFile
,
StandardCopyOption
.
REPLACE_EXISTING
);
InputFile
tempFile
=
new
InputFile
(
jarFile
.
toFile
());
tempFile
.
loadFromZip
(
ext
);
List
<
DexFile
>
dexF
iles
=
tempFile
.
getDexFiles
();
if
(!
dexF
iles
.
isEmpty
())
{
index
+=
dexF
iles
.
size
();
this
.
dexFiles
.
addAll
(
dexF
iles
);
List
<
DexFile
>
f
iles
=
tempFile
.
getDexFiles
();
if
(!
f
iles
.
isEmpty
())
{
index
+=
f
iles
.
size
();
this
.
dexFiles
.
addAll
(
f
iles
);
}
}
}
...
...
jadx-core/src/test/java/jadx/api/JadxDecompilerTest.java
浏览文件 @
ab970840
...
...
@@ -2,22 +2,39 @@ package jadx.api;
import
java.io.File
;
import
org.
junit.jupiter.api.Disabled
;
import
org.
hamcrest.Matchers
;
import
org.junit.jupiter.api.Test
;
import
jadx.core.utils.files.FileUtils
;
import
jadx.core.utils.files.InputFileTest
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
public
class
JadxDecompilerTest
{
@Test
@Disabled
public
void
testExampleUsage
()
{
File
sampleApk
=
InputFileTest
.
getFileFromSampleDir
(
"app-with-fake-dex.apk"
);
File
outDir
=
FileUtils
.
createTempDir
(
"jadx-usage-example"
).
toFile
();
// test simple apk loading
JadxArgs
args
=
new
JadxArgs
();
args
.
getInputFiles
().
add
(
new
File
(
"test.apk"
)
);
args
.
setOutDir
(
new
File
(
"jadx-test-output"
)
);
args
.
getInputFiles
().
add
(
sampleApk
);
args
.
setOutDir
(
outDir
);
JadxDecompiler
jadx
=
new
JadxDecompiler
(
args
);
jadx
.
load
();
jadx
.
save
();
jadx
.
printErrorsReport
();
// test class print
for
(
JavaClass
cls
:
jadx
.
getClasses
())
{
System
.
out
.
println
(
cls
.
getCode
());
}
assertThat
(
jadx
.
getClasses
(),
Matchers
.
hasSize
(
3
));
assertThat
(
jadx
.
getErrorsCount
(),
Matchers
.
is
(
0
));
}
// TODO
make
more tests
// TODO
add
more tests
}
jadx-core/src/test/java/jadx/api/JadxInternalAccess.java
浏览文件 @
ab970840
package
jadx.api
;
import
java.util.List
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
public
class
JadxInternalAccess
{
public
static
RootNode
getRoot
(
JadxDecompiler
d
)
{
return
d
.
getRoot
();
}
public
static
List
<
IDexTreeVisitor
>
getPassList
(
JadxDecompiler
d
)
{
return
d
.
getPasses
();
}
}
jadx-core/src/test/java/jadx/core/utils/files/InputFileTest.java
浏览文件 @
ab970840
...
...
@@ -14,7 +14,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import
static
org
.
hamcrest
.
Matchers
.
hasSize
;
import
static
org
.
hamcrest
.
Matchers
.
notNullValue
;
class
InputFileTest
{
public
class
InputFileTest
{
private
static
final
String
TEST_SAMPLES_DIR
=
"test-samples/"
;
@Test
...
...
@@ -28,7 +28,7 @@ class InputFileTest {
assertThat
(
inputFile
.
getDexFiles
(),
hasSize
(
1
));
}
p
rivate
static
File
getFileFromSampleDir
(
String
fileName
)
{
p
ublic
static
File
getFileFromSampleDir
(
String
fileName
)
{
URL
resource
=
InputFileTest
.
class
.
getClassLoader
().
getResource
(
TEST_SAMPLES_DIR
+
fileName
);
assertThat
(
resource
,
notNullValue
());
String
pathStr
=
resource
.
getFile
();
...
...
jadx-core/src/test/java/jadx/tests/api/IntegrationTest.java
浏览文件 @
ab970840
...
...
@@ -22,11 +22,12 @@ import java.util.jar.JarOutputStream;
import
org.junit.jupiter.api.BeforeEach
;
import
jadx.api.ICodeInfo
;
import
jadx.api.JadxArgs
;
import
jadx.api.JadxDecompiler
;
import
jadx.api.JadxInternalAccess
;
import
jadx.core.ProcessClass
;
import
jadx.core.codegen.CodeGen
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.AttrList
;
...
...
@@ -34,8 +35,6 @@ import jadx.core.dex.attributes.IAttributeNode;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.visitors.DepthTraversal
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.utils.files.FileUtils
;
import
jadx.core.xmlgen.ResourceStorage
;
import
jadx.core.xmlgen.entry.ResourceEntry
;
...
...
@@ -44,6 +43,8 @@ import jadx.tests.api.compiler.StaticCompiler;
import
jadx.tests.api.utils.TestUtils
;
import
static
jadx
.
core
.
utils
.
files
.
FileUtils
.
addFileToJar
;
import
static
org
.
apache
.
commons
.
lang3
.
StringUtils
.
leftPad
;
import
static
org
.
apache
.
commons
.
lang3
.
StringUtils
.
rightPad
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
empty
;
...
...
@@ -82,6 +83,7 @@ public abstract class IntegrationTest extends TestUtils {
protected
Map
<
Integer
,
String
>
resMap
=
Collections
.
emptyMap
();
private
boolean
allowWarnInCode
;
private
boolean
printLineNumbers
;
private
DynamicCompiler
dynamicCompiler
;
...
...
@@ -161,14 +163,18 @@ public abstract class IntegrationTest extends TestUtils {
protected
void
decompileAndCheck
(
JadxDecompiler
d
,
List
<
ClassNode
>
clsList
)
{
if
(
unloadCls
)
{
clsList
.
forEach
(
cls
->
decompile
(
d
,
cls
));
clsList
.
forEach
(
cls
->
cls
.
decompile
(
));
}
else
{
clsList
.
forEach
(
cls
->
decompileWithoutUnload
(
d
,
cls
));
}
for
(
ClassNode
cls
:
clsList
)
{
System
.
out
.
println
(
"-----------------------------------------------------------"
);
System
.
out
.
println
(
cls
.
getCode
());
if
(
printLineNumbers
)
{
printCodeWithLineNumbers
(
cls
.
getCode
());
}
else
{
System
.
out
.
println
(
cls
.
getCode
());
}
}
System
.
out
.
println
(
"-----------------------------------------------------------"
);
...
...
@@ -177,6 +183,22 @@ public abstract class IntegrationTest extends TestUtils {
clsList
.
forEach
(
this
::
runAutoCheck
);
}
private
void
printCodeWithLineNumbers
(
ICodeInfo
code
)
{
String
codeStr
=
code
.
getCodeStr
();
Map
<
Integer
,
Integer
>
lineMapping
=
code
.
getLineMapping
();
String
[]
lines
=
codeStr
.
split
(
CodeWriter
.
NL
);
for
(
int
i
=
0
;
i
<
lines
.
length
;
i
++)
{
String
line
=
lines
[
i
];
int
curLine
=
i
+
1
;
String
lineNumStr
=
"/* "
+
leftPad
(
String
.
valueOf
(
curLine
),
3
)
+
" */"
;
Integer
sourceLine
=
lineMapping
.
get
(
curLine
);
if
(
sourceLine
!=
null
)
{
lineNumStr
+=
" /* "
+
sourceLine
+
" */"
;
}
System
.
out
.
println
(
rightPad
(
lineNumStr
,
20
)
+
line
);
}
}
private
void
insertResources
(
RootNode
root
)
{
if
(
resMap
.
isEmpty
())
{
return
;
...
...
@@ -191,23 +213,15 @@ public abstract class IntegrationTest extends TestUtils {
root
.
processResources
(
resStorage
);
}
protected
void
decompile
(
JadxDecompiler
jadx
,
ClassNode
cls
)
{
List
<
IDexTreeVisitor
>
passes
=
JadxInternalAccess
.
getPassList
(
jadx
);
ProcessClass
.
process
(
cls
,
passes
,
true
);
}
protected
void
decompileWithoutUnload
(
JadxDecompiler
jadx
,
ClassNode
cls
)
{
cls
.
load
();
for
(
IDexTreeVisitor
visitor
:
JadxInternalAccess
.
getPassList
(
jadx
))
{
DepthTraversal
.
visit
(
visitor
,
cls
);
}
cls
.
loadAndProcess
();
generateClsCode
(
cls
);
// don't unload class
}
protected
void
generateClsCode
(
ClassNode
cls
)
{
try
{
CodeGen
.
generate
(
cls
);
cls
.
setCode
(
CodeGen
.
generate
(
cls
)
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
fail
(
e
.
getMessage
());
...
...
@@ -452,6 +466,10 @@ public abstract class IntegrationTest extends TestUtils {
allowWarnInCode
=
true
;
}
protected
void
printLineNumbers
()
{
printLineNumbers
=
true
;
}
// Use only for debug purpose
@Deprecated
protected
void
outputCFG
()
{
...
...
jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java
浏览文件 @
ab970840
...
...
@@ -2,7 +2,6 @@ package jadx.tests.external;
import
java.io.File
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.apache.commons.lang3.StringUtils
;
...
...
@@ -15,12 +14,10 @@ import jadx.api.JadxArgs;
import
jadx.api.JadxDecompiler
;
import
jadx.api.JadxInternalAccess
;
import
jadx.api.JavaClass
;
import
jadx.core.ProcessClass
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.nodes.RootNode
;
import
jadx.core.dex.visitors.IDexTreeVisitor
;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
jadx.tests.api.IntegrationTest
;
...
...
@@ -68,13 +65,12 @@ public abstract class BaseExternalTest extends IntegrationTest {
}
private
void
processByPatterns
(
JadxDecompiler
jadx
,
String
clsPattern
,
@Nullable
String
mthPattern
)
{
List
<
IDexTreeVisitor
>
passes
=
JadxInternalAccess
.
getPassList
(
jadx
);
RootNode
root
=
JadxInternalAccess
.
getRoot
(
jadx
);
int
processed
=
0
;
for
(
ClassNode
classNode
:
root
.
getClasses
(
true
))
{
String
clsFullName
=
classNode
.
getClassInfo
().
getFullName
();
if
(
clsFullName
.
equals
(
clsPattern
))
{
if
(
processCls
(
mthPattern
,
passes
,
classNode
))
{
if
(
processCls
(
mthPattern
,
classNode
))
{
processed
++;
}
}
...
...
@@ -82,7 +78,7 @@ public abstract class BaseExternalTest extends IntegrationTest {
assertThat
(
"No classes processed"
,
processed
,
greaterThan
(
0
));
}
private
boolean
processCls
(
@Nullable
String
mthPattern
,
List
<
IDexTreeVisitor
>
passes
,
ClassNode
classNode
)
{
private
boolean
processCls
(
@Nullable
String
mthPattern
,
ClassNode
classNode
)
{
classNode
.
load
();
boolean
decompile
=
false
;
if
(
mthPattern
==
null
)
{
...
...
@@ -99,7 +95,7 @@ public abstract class BaseExternalTest extends IntegrationTest {
return
false
;
}
try
{
ProcessClass
.
process
(
classNode
,
passes
,
true
);
classNode
.
decompile
(
);
}
catch
(
Exception
e
)
{
throw
new
JadxRuntimeException
(
"Class process failed"
,
e
);
}
...
...
jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java
浏览文件 @
ab970840
...
...
@@ -5,7 +5,6 @@ import java.util.Map;
import
org.junit.jupiter.api.Test
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
...
...
@@ -16,6 +15,7 @@ public class TestLineNumbers2 extends IntegrationTest {
public
static
class
TestCls
{
private
WeakReference
<
TestCls
>
f
;
// keep at line 18
public
TestCls
(
TestCls
s
)
{
}
...
...
@@ -35,10 +35,10 @@ public class TestLineNumbers2 extends IntegrationTest {
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
CodeWriter
codeWriter
=
cls
.
getCode
();
printLineNumbers
();
Map
<
Integer
,
Integer
>
lineMapping
=
codeWriter
.
getLineMapping
();
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
Map
<
Integer
,
Integer
>
lineMapping
=
cls
.
getCode
().
getLineMapping
();
assertEquals
(
"{8=18, 11=22, 12=23, 13=24, 14=28, 16=25, 17=26, 18=28, 21=31, 22=32}"
,
lineMapping
.
toString
());
}
...
...
jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java
浏览文件 @
ab970840
...
...
@@ -3,6 +3,7 @@ package jadx.tests.integration.debuginfo;
import
org.junit.jupiter.api.Test
;
import
jadx.NotYetImplemented
;
import
jadx.api.ICodeInfo
;
import
jadx.core.codegen.CodeWriter
;
import
jadx.core.dex.attributes.nodes.LineAttrNode
;
import
jadx.core.dex.nodes.ClassNode
;
...
...
@@ -51,30 +52,30 @@ public class TestReturnSourceLine extends IntegrationTest {
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
CodeWriter
codeWriter
=
cls
.
getCode
();
String
code
=
code
Writer
.
toString
();
ICodeInfo
codeInfo
=
cls
.
getCode
();
String
code
=
code
Info
.
toString
();
String
[]
lines
=
code
.
split
(
CodeWriter
.
NL
);
MethodNode
test1
=
cls
.
searchMethodByShortId
(
"test1(Z)I"
);
checkLine
(
lines
,
code
Writer
,
test1
,
3
,
"return 1;"
);
checkLine
(
lines
,
code
Info
,
test1
,
3
,
"return 1;"
);
MethodNode
test2
=
cls
.
searchMethodByShortId
(
"test2(I)I"
);
checkLine
(
lines
,
code
Writer
,
test2
,
3
,
"return v - 1;"
);
checkLine
(
lines
,
code
Info
,
test2
,
3
,
"return v - 1;"
);
}
@Test
@NotYetImplemented
public
void
test2
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
CodeWriter
codeWriter
=
cls
.
getCode
();
String
code
=
code
Writer
.
toString
();
ICodeInfo
codeInfo
=
cls
.
getCode
();
String
code
=
code
Info
.
toString
();
String
[]
lines
=
code
.
split
(
CodeWriter
.
NL
);
MethodNode
test3
=
cls
.
searchMethodByShortId
(
"test3(I)I"
);
checkLine
(
lines
,
code
Writer
,
test3
,
3
,
"return v;"
);
checkLine
(
lines
,
code
Info
,
test3
,
3
,
"return v;"
);
}
private
static
void
checkLine
(
String
[]
lines
,
CodeWriter
cw
,
LineAttrNode
node
,
int
offset
,
String
str
)
{
private
static
void
checkLine
(
String
[]
lines
,
ICodeInfo
cw
,
LineAttrNode
node
,
int
offset
,
String
str
)
{
int
decompiledLine
=
node
.
getDecompiledLine
()
+
offset
;
assertThat
(
lines
[
decompiledLine
-
1
],
containsOne
(
str
));
Integer
sourceLine
=
cw
.
getLineMapping
().
get
(
decompiledLine
);
...
...
jadx-core/src/test/java/jadx/tests/integration/loops/TestComplexWhileLoop.java
0 → 100644
浏览文件 @
ab970840
package
jadx.tests.integration.loops
;
import
org.junit.jupiter.api.Test
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
public
class
TestComplexWhileLoop
extends
IntegrationTest
{
public
static
class
TestCls
{
public
static
String
test
(
String
[]
arr
)
{
int
index
=
0
;
int
length
=
arr
.
length
;
String
str
;
while
((
str
=
arr
[
index
])
!=
null
)
{
if
(
str
.
length
()
==
1
)
{
return
str
.
trim
();
}
if
(++
index
>=
length
)
{
index
=
0
;
}
}
System
.
out
.
println
(
"loop end"
);
return
""
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
not
(
containsString
(
"for (int at = 0; at < len; at = endAt) {"
)));
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录