Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
J
jadx
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open-source
jadx
Commits
4e6c5cb2
Commit
4e6c5cb2
authored
Apr 25, 2015
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: inline anonymous classes with arguments
parent
a9c0185b
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
443 additions
and
69 deletions
+443
-69
InsnGen.java
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+50
-30
MethodGen.java
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
+5
-0
AFlag.java
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
+2
-0
FieldReplaceAttr.java
...java/jadx/core/dex/attributes/nodes/FieldReplaceAttr.java
+26
-11
SSAVar.java
...src/main/java/jadx/core/dex/instructions/args/SSAVar.java
+2
-1
ClassModifier.java
...e/src/main/java/jadx/core/dex/visitors/ClassModifier.java
+1
-2
CodeShrinker.java
...re/src/main/java/jadx/core/dex/visitors/CodeShrinker.java
+3
-1
DebugInfoVisitor.java
...rc/main/java/jadx/core/dex/visitors/DebugInfoVisitor.java
+2
-1
DotGraphVisitor.java
...src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java
+7
-0
ModVisitor.java
...core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
+112
-2
PrepareForCodeGen.java
...c/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java
+5
-0
SimplifyVisitor.java
...src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
+23
-19
ProcessTryCatchRegions.java
...adx/core/dex/visitors/regions/ProcessTryCatchRegions.java
+1
-1
TestAnonymousClass10.java
...va/jadx/tests/integration/inner/TestAnonymousClass10.java
+47
-0
TestAnonymousClass6.java
...ava/jadx/tests/integration/inner/TestAnonymousClass6.java
+36
-0
TestAnonymousClass7.java
...ava/jadx/tests/integration/inner/TestAnonymousClass7.java
+37
-0
TestAnonymousClass8.java
...ava/jadx/tests/integration/inner/TestAnonymousClass8.java
+39
-0
TestAnonymousClass9.java
...ava/jadx/tests/integration/inner/TestAnonymousClass9.java
+45
-0
TestConstructor.java
...-core/src/test/java/jadx/tests/smali/TestConstructor.java
+0
-1
No files found.
jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
View file @
4e6c5cb2
...
...
@@ -29,6 +29,7 @@ import jadx.core.dex.instructions.args.InsnWrapArg;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.Named
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.args.SSAVar
;
import
jadx.core.dex.instructions.mods.ConstructorInsn
;
import
jadx.core.dex.instructions.mods.TernaryInsn
;
import
jadx.core.dex.nodes.ClassNode
;
...
...
@@ -123,6 +124,9 @@ public class InsnGen {
}
public
void
declareVar
(
CodeWriter
code
,
RegisterArg
arg
)
{
if
(
arg
.
getSVar
().
contains
(
AFlag
.
FINAL
))
{
code
.
add
(
"final "
);
}
useType
(
code
,
arg
.
getType
());
code
.
add
(
' '
);
code
.
add
(
mgen
.
getNameGen
().
assignArg
(
arg
));
...
...
@@ -144,16 +148,19 @@ public class InsnGen {
if
(
fieldNode
!=
null
)
{
FieldReplaceAttr
replace
=
fieldNode
.
get
(
AType
.
FIELD_REPLACE
);
if
(
replace
!=
null
)
{
FieldInfo
info
=
replace
.
getFieldInfo
();
if
(
replace
.
isOuterClass
())
{
useClass
(
code
,
info
.
getDeclClass
());
code
.
add
(
".this"
);
switch
(
replace
.
getReplaceType
())
{
case
CLASS_INSTANCE:
useClass
(
code
,
replace
.
getClsRef
());
code
.
add
(
".this"
);
break
;
case
VAR:
addArg
(
code
,
replace
.
getVarRef
());
break
;
}
return
;
}
}
addArgDot
(
code
,
arg
);
fieldNode
=
mth
.
dex
().
resolveField
(
field
);
if
(
fieldNode
!=
null
)
{
code
.
attachAnnotation
(
fieldNode
);
}
...
...
@@ -531,30 +538,7 @@ public class InsnGen {
throws
CodegenException
{
ClassNode
cls
=
mth
.
dex
().
resolveClass
(
insn
.
getClassType
());
if
(
cls
!=
null
&&
cls
.
contains
(
AFlag
.
ANONYMOUS_CLASS
)
&&
!
fallback
)
{
// anonymous class construction
ArgType
parent
;
if
(
cls
.
getInterfaces
().
size
()
==
1
)
{
parent
=
cls
.
getInterfaces
().
get
(
0
);
}
else
{
parent
=
cls
.
getSuperClass
();
}
cls
.
add
(
AFlag
.
DONT_GENERATE
);
MethodNode
defCtr
=
cls
.
getDefaultConstructor
();
if
(
defCtr
!=
null
)
{
if
(
RegionUtils
.
notEmpty
(
defCtr
.
getRegion
()))
{
defCtr
.
add
(
AFlag
.
ANONYMOUS_CONSTRUCTOR
);
}
else
{
defCtr
.
add
(
AFlag
.
DONT_GENERATE
);
}
}
code
.
add
(
"new "
);
if
(
parent
==
null
)
{
code
.
add
(
"Object"
);
}
else
{
useClass
(
code
,
parent
);
}
code
.
add
(
"() "
);
new
ClassGen
(
cls
,
mgen
.
getClassGen
().
getParentGen
()).
addClassBody
(
code
);
inlineAnonymousConstr
(
code
,
cls
,
insn
);
return
;
}
if
(
insn
.
isSelf
())
{
...
...
@@ -568,7 +552,37 @@ public class InsnGen {
code
.
add
(
"new "
);
useClass
(
code
,
insn
.
getClassType
());
}
generateMethodArguments
(
code
,
insn
,
0
,
mth
.
dex
().
resolveMethod
(
insn
.
getCallMth
()));
MethodNode
callMth
=
mth
.
dex
().
resolveMethod
(
insn
.
getCallMth
());
generateMethodArguments
(
code
,
insn
,
0
,
callMth
);
}
private
void
inlineAnonymousConstr
(
CodeWriter
code
,
ClassNode
cls
,
ConstructorInsn
insn
)
throws
CodegenException
{
// anonymous class construction
ArgType
parent
;
if
(
cls
.
getInterfaces
().
size
()
==
1
)
{
parent
=
cls
.
getInterfaces
().
get
(
0
);
}
else
{
parent
=
cls
.
getSuperClass
();
}
cls
.
add
(
AFlag
.
DONT_GENERATE
);
MethodNode
defCtr
=
cls
.
getDefaultConstructor
();
if
(
defCtr
!=
null
)
{
if
(
RegionUtils
.
notEmpty
(
defCtr
.
getRegion
()))
{
defCtr
.
add
(
AFlag
.
ANONYMOUS_CONSTRUCTOR
);
}
else
{
defCtr
.
add
(
AFlag
.
DONT_GENERATE
);
}
}
code
.
add
(
"new "
);
if
(
parent
==
null
)
{
code
.
add
(
"Object"
);
}
else
{
useClass
(
code
,
parent
);
}
MethodNode
callMth
=
mth
.
dex
().
resolveMethod
(
insn
.
getCallMth
());
generateMethodArguments
(
code
,
insn
,
0
,
callMth
);
code
.
add
(
' '
);
new
ClassGen
(
cls
,
mgen
.
getClassGen
().
getParentGen
()).
addClassBody
(
code
);
}
private
void
makeInvoke
(
InvokeNode
insn
,
CodeWriter
code
)
throws
CodegenException
{
...
...
@@ -631,6 +645,12 @@ public class InsnGen {
boolean
overloaded
=
callMth
!=
null
&&
callMth
.
isArgsOverload
();
for
(
int
i
=
k
;
i
<
argsCount
;
i
++)
{
InsnArg
arg
=
insn
.
getArg
(
i
);
if
(
arg
.
isRegister
())
{
SSAVar
sVar
=
((
RegisterArg
)
arg
).
getSVar
();
if
(
sVar
!=
null
&&
sVar
.
contains
(
AFlag
.
SKIP_ARG
))
{
continue
;
}
}
boolean
cast
=
overloaded
&&
processOverloadedArg
(
code
,
callMth
,
arg
,
i
-
startArgNum
);
if
(!
cast
&&
i
==
argsCount
-
1
&&
processVarArg
(
code
,
callMth
,
arg
))
{
continue
;
...
...
jadx-core/src/main/java/jadx/core/codegen/MethodGen.java
View file @
4e6c5cb2
...
...
@@ -8,6 +8,7 @@ import jadx.core.dex.info.AccessInfo;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.args.SSAVar
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.trycatch.CatchAttr
;
...
...
@@ -126,6 +127,10 @@ public class MethodGen {
if
(
paramsAnnotation
!=
null
)
{
annotationGen
.
addForParameter
(
argsCode
,
paramsAnnotation
,
i
);
}
SSAVar
argSVar
=
arg
.
getSVar
();
if
(
argSVar
!=
null
&&
argSVar
.
contains
(
AFlag
.
FINAL
))
{
argsCode
.
add
(
"final "
);
}
if
(!
it
.
hasNext
()
&&
mth
.
getAccessFlags
().
isVarArgs
())
{
// change last array argument to varargs
ArgType
type
=
arg
.
getType
();
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java
View file @
4e6c5cb2
...
...
@@ -8,6 +8,7 @@ public enum AFlag {
LOOP_END
,
SYNTHETIC
,
FINAL
,
// SSAVar attribute for make var final
RETURN
,
// block contains only return instruction
ORIG_RETURN
,
...
...
@@ -22,6 +23,7 @@ public enum AFlag {
REMOVE
,
SKIP_FIRST_ARG
,
SKIP_ARG
,
// skip argument in invoke call
ANONYMOUS_CONSTRUCTOR
,
ANONYMOUS_CLASS
,
...
...
jadx-core/src/main/java/jadx/core/dex/attributes/nodes/FieldReplaceAttr.java
View file @
4e6c5cb2
...
...
@@ -2,24 +2,39 @@ package jadx.core.dex.attributes.nodes;
import
jadx.core.dex.attributes.AType
;
import
jadx.core.dex.attributes.IAttribute
;
import
jadx.core.dex.info.FieldInfo
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.instructions.args.InsnArg
;
public
class
FieldReplaceAttr
implements
IAttribute
{
private
final
FieldInfo
fieldInfo
;
private
final
boolean
isOuterClass
;
public
enum
ReplaceWith
{
CLASS_INSTANCE
,
VAR
}
private
final
ReplaceWith
replaceType
;
private
final
Object
replaceObj
;
public
FieldReplaceAttr
(
ClassInfo
cls
)
{
this
.
replaceType
=
ReplaceWith
.
CLASS_INSTANCE
;
this
.
replaceObj
=
cls
;
}
public
FieldReplaceAttr
(
InsnArg
reg
)
{
this
.
replaceType
=
ReplaceWith
.
VAR
;
this
.
replaceObj
=
reg
;
}
public
FieldReplaceAttr
(
FieldInfo
fieldInfo
,
boolean
isOuterClass
)
{
this
.
fieldInfo
=
fieldInfo
;
this
.
isOuterClass
=
isOuterClass
;
public
ReplaceWith
getReplaceType
()
{
return
replaceType
;
}
public
FieldInfo
getFieldInfo
()
{
return
fieldInfo
;
public
ClassInfo
getClsRef
()
{
return
(
ClassInfo
)
replaceObj
;
}
public
boolean
isOuterClass
()
{
return
isOuterClass
;
public
InsnArg
getVarRef
()
{
return
(
InsnArg
)
replaceObj
;
}
@Override
...
...
@@ -29,6 +44,6 @@ public class FieldReplaceAttr implements IAttribute {
@Override
public
String
toString
()
{
return
"REPLACE: "
+
fieldInfo
;
return
"REPLACE: "
+
replaceType
+
" "
+
replaceObj
;
}
}
jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java
View file @
4e6c5cb2
package
jadx
.
core
.
dex
.
instructions
.
args
;
import
jadx.core.dex.attributes.AttrNode
;
import
jadx.core.dex.instructions.PhiInsn
;
import
java.util.ArrayList
;
...
...
@@ -8,7 +9,7 @@ import java.util.List;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
public
class
SSAVar
{
public
class
SSAVar
extends
AttrNode
{
private
final
int
regNum
;
private
final
int
version
;
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java
View file @
4e6c5cb2
...
...
@@ -76,8 +76,7 @@ public class ClassModifier extends AbstractVisitor {
}
}
if
(
found
!=
0
)
{
FieldInfo
replace
=
FieldInfo
.
from
(
cls
.
dex
(),
parentClass
,
"this"
,
parentClass
.
getType
());
field
.
addAttr
(
new
FieldReplaceAttr
(
replace
,
true
));
field
.
addAttr
(
new
FieldReplaceAttr
(
parentClass
));
field
.
add
(
AFlag
.
DONT_GENERATE
);
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java
View file @
4e6c5cb2
...
...
@@ -210,7 +210,9 @@ public class CodeShrinker extends AbstractVisitor {
// }
SSAVar
sVar
=
arg
.
getSVar
();
// allow inline only one use arg or 'this'
if
(
sVar
==
null
||
sVar
.
getVariableUseCount
()
!=
1
&&
!
arg
.
isThis
())
{
if
(
sVar
==
null
||
sVar
.
getVariableUseCount
()
!=
1
&&
!
arg
.
isThis
()
||
sVar
.
contains
(
AFlag
.
DONT_INLINE
))
{
continue
;
}
InsnNode
assignInsn
=
sVar
.
getAssign
().
getParentInsn
();
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/DebugInfoVisitor.java
View file @
4e6c5cb2
...
...
@@ -18,6 +18,7 @@ public class DebugInfoVisitor extends AbstractVisitor {
DebugInfoParser
debugInfoParser
=
new
DebugInfoParser
(
mth
,
debugOffset
,
insnArr
);
debugInfoParser
.
process
();
// set method source line from first instruction
if
(
insnArr
.
length
!=
0
)
{
for
(
InsnNode
insn
:
insnArr
)
{
if
(
insn
!=
null
)
{
...
...
@@ -30,7 +31,7 @@ public class DebugInfoVisitor extends AbstractVisitor {
}
}
if
(!
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
))
{
// fix debug for splitter 'return' instructions
// fix debug
info
for splitter 'return' instructions
for
(
BlockNode
exit
:
mth
.
getExitBlocks
())
{
InsnNode
ret
=
BlockUtils
.
getLastInsn
(
exit
);
if
(
ret
==
null
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java
View file @
4e6c5cb2
...
...
@@ -23,8 +23,13 @@ import java.util.HashSet;
import
java.util.List
;
import
java.util.Set
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
public
class
DotGraphVisitor
extends
AbstractVisitor
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
DotGraphVisitor
.
class
);
private
static
final
String
NL
=
"\\l"
;
private
static
final
boolean
PRINT_DOMINATORS
=
false
;
...
...
@@ -52,6 +57,8 @@ public class DotGraphVisitor extends AbstractVisitor {
this
.
dir
=
outDir
;
this
.
useRegions
=
useRegions
;
this
.
rawInsn
=
rawInsn
;
LOG
.
debug
(
"DOT {}{}graph dump dir: {}"
,
useRegions
?
"regions "
:
""
,
rawInsn
?
"raw "
:
""
,
outDir
.
getAbsolutePath
());
}
@Override
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
View file @
4e6c5cb2
...
...
@@ -2,7 +2,11 @@ package jadx.core.dex.visitors;
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.FieldReplaceAttr
;
import
jadx.core.dex.info.ClassInfo
;
import
jadx.core.dex.info.FieldInfo
;
import
jadx.core.dex.info.MethodInfo
;
import
jadx.core.dex.instructions.ArithNode
;
import
jadx.core.dex.instructions.ConstClassNode
;
...
...
@@ -34,7 +38,10 @@ import jadx.core.utils.InstructionRemover;
import
jadx.core.utils.exceptions.JadxRuntimeException
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -43,6 +50,11 @@ import org.slf4j.LoggerFactory;
* Visitor for modify method instructions
* (remove, replace, process exception handlers)
*/
@JadxVisitor
(
name
=
"ModVisitor"
,
desc
=
"Modify method instructions"
,
runBefore
=
CodeShrinker
.
class
)
public
class
ModVisitor
extends
AbstractVisitor
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ModVisitor
.
class
);
...
...
@@ -197,7 +209,6 @@ public class ModVisitor extends AbstractVisitor {
remover
.
add
(
insn
);
return
;
}
replaceInsn
(
block
,
insnNumber
,
co
);
if
(
co
.
isNewInstance
())
{
InsnNode
newInstInsn
=
removeAssignChain
(
instArgAssignInsn
,
remover
,
InsnType
.
NEW_INSTANCE
);
if
(
newInstInsn
!=
null
)
{
...
...
@@ -217,8 +228,107 @@ public class ModVisitor extends AbstractVisitor {
}
ConstructorInsn
replace
=
processConstructor
(
mth
,
co
);
if
(
replace
!=
null
)
{
replaceInsn
(
block
,
insnNumber
,
replace
);
co
=
replace
;
}
replaceInsn
(
block
,
insnNumber
,
co
);
processAnonymousConstructor
(
mth
,
co
);
}
private
static
void
processAnonymousConstructor
(
MethodNode
mth
,
ConstructorInsn
co
)
{
MethodInfo
callMth
=
co
.
getCallMth
();
MethodNode
callMthNode
=
mth
.
dex
().
resolveMethod
(
callMth
);
if
(
callMthNode
==
null
)
{
return
;
}
ClassNode
classNode
=
callMthNode
.
getParentClass
();
ClassInfo
classInfo
=
classNode
.
getClassInfo
();
ClassNode
parentClass
=
mth
.
getParentClass
();
if
(!
classInfo
.
isInner
()
||
!
Character
.
isDigit
(
classInfo
.
getShortName
().
charAt
(
0
))
||
!
parentClass
.
getInnerClasses
().
contains
(
classNode
))
{
return
;
}
if
(!
classNode
.
getAccessFlags
().
isStatic
()
&&
(
callMth
.
getArgsCount
()
==
0
||
!
callMth
.
getArgumentsTypes
().
get
(
0
).
equals
(
parentClass
.
getClassInfo
().
getType
())))
{
return
;
}
// TODO: calculate this constructor and other constructor usage
Map
<
InsnArg
,
FieldNode
>
argsMap
=
getArgsToFieldsMapping
(
callMthNode
,
co
);
if
(
argsMap
.
isEmpty
())
{
return
;
}
// all checks passed
classNode
.
add
(
AFlag
.
ANONYMOUS_CLASS
);
callMthNode
.
add
(
AFlag
.
DONT_GENERATE
);
for
(
Map
.
Entry
<
InsnArg
,
FieldNode
>
entry
:
argsMap
.
entrySet
())
{
FieldNode
field
=
entry
.
getValue
();
if
(
field
==
null
)
{
continue
;
}
InsnArg
arg
=
entry
.
getKey
();
field
.
addAttr
(
new
FieldReplaceAttr
(
arg
));
field
.
add
(
AFlag
.
DONT_GENERATE
);
if
(
arg
.
isRegister
())
{
RegisterArg
reg
=
(
RegisterArg
)
arg
;
SSAVar
sVar
=
reg
.
getSVar
();
if
(
sVar
!=
null
)
{
sVar
.
add
(
AFlag
.
FINAL
);
sVar
.
add
(
AFlag
.
DONT_INLINE
);
sVar
.
add
(
AFlag
.
SKIP_ARG
);
}
}
}
}
private
static
Map
<
InsnArg
,
FieldNode
>
getArgsToFieldsMapping
(
MethodNode
callMthNode
,
ConstructorInsn
co
)
{
Map
<
InsnArg
,
FieldNode
>
map
=
new
LinkedHashMap
<
InsnArg
,
FieldNode
>();
ClassNode
parentClass
=
callMthNode
.
getParentClass
();
List
<
RegisterArg
>
argList
=
callMthNode
.
getArguments
(
false
);
int
startArg
=
parentClass
.
getAccessFlags
().
isStatic
()
?
0
:
1
;
int
argsCount
=
argList
.
size
();
for
(
int
i
=
startArg
;
i
<
argsCount
;
i
++)
{
RegisterArg
arg
=
argList
.
get
(
i
);
InsnNode
useInsn
=
getParentInsnSkipMove
(
arg
);
if
(
useInsn
==
null
)
{
return
Collections
.
emptyMap
();
}
FieldNode
fieldNode
=
null
;
if
(
useInsn
.
getType
()
==
InsnType
.
IPUT
)
{
FieldInfo
field
=
(
FieldInfo
)
((
IndexInsnNode
)
useInsn
).
getIndex
();
fieldNode
=
parentClass
.
searchField
(
field
);
if
(
fieldNode
==
null
||
!
fieldNode
.
getAccessFlags
().
isSynthetic
())
{
return
Collections
.
emptyMap
();
}
}
else
if
(
useInsn
.
getType
()
==
InsnType
.
CONSTRUCTOR
)
{
ConstructorInsn
superConstr
=
(
ConstructorInsn
)
useInsn
;
if
(!
superConstr
.
isSuper
())
{
return
Collections
.
emptyMap
();
}
}
else
{
return
Collections
.
emptyMap
();
}
map
.
put
(
co
.
getArg
(
i
),
fieldNode
);
}
return
map
;
}
private
static
InsnNode
getParentInsnSkipMove
(
RegisterArg
arg
)
{
SSAVar
sVar
=
arg
.
getSVar
();
if
(
sVar
.
getUseCount
()
!=
1
)
{
return
null
;
}
RegisterArg
useArg
=
sVar
.
getUseList
().
get
(
0
);
InsnNode
parentInsn
=
useArg
.
getParentInsn
();
if
(
parentInsn
==
null
)
{
return
null
;
}
if
(
parentInsn
.
getType
()
==
InsnType
.
MOVE
)
{
return
getParentInsnSkipMove
(
parentInsn
.
getResult
());
}
return
parentInsn
;
}
/**
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java
View file @
4e6c5cb2
...
...
@@ -21,6 +21,11 @@ import java.util.List;
* most of this modification breaks register dependencies,
* so this pass must be just before CodeGen.
*/
@JadxVisitor
(
name
=
"PrepareForCodeGen"
,
desc
=
"Prepare instructions for code generation pass"
,
runAfter
=
{
CodeShrinker
.
class
,
ClassModifier
.
class
}
)
public
class
PrepareForCodeGen
extends
AbstractVisitor
{
@Override
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
View file @
4e6c5cb2
...
...
@@ -77,25 +77,7 @@ public class SimplifyVisitor extends AbstractVisitor {
return
convertFieldArith
(
mth
,
insn
);
case
CHECK_CAST:
InsnArg
castArg
=
insn
.
getArg
(
0
);
ArgType
argType
=
castArg
.
getType
();
// Don't removes CHECK_CAST for wrapped INVOKE if invoked method returns different type
if
(
castArg
.
isInsnWrap
())
{
InsnNode
wrapInsn
=
((
InsnWrapArg
)
castArg
).
getWrapInsn
();
if
(
wrapInsn
.
getType
()
==
InsnType
.
INVOKE
)
{
argType
=
((
InvokeNode
)
wrapInsn
).
getCallMth
().
getReturnType
();
}
}
ArgType
castToType
=
(
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
();
if
(!
ArgType
.
isCastNeeded
(
mth
.
dex
(),
argType
,
castToType
))
{
InsnNode
insnNode
=
new
InsnNode
(
InsnType
.
MOVE
,
1
);
insnNode
.
setOffset
(
insn
.
getOffset
());
insnNode
.
setResult
(
insn
.
getResult
());
insnNode
.
addArg
(
castArg
);
return
insnNode
;
}
break
;
return
processCast
(
mth
,
insn
);
case
MOVE:
InsnArg
firstArg
=
insn
.
getArg
(
0
);
...
...
@@ -114,6 +96,28 @@ public class SimplifyVisitor extends AbstractVisitor {
return
null
;
}
private
static
InsnNode
processCast
(
MethodNode
mth
,
InsnNode
insn
)
{
InsnArg
castArg
=
insn
.
getArg
(
0
);
ArgType
argType
=
castArg
.
getType
();
// Don't removes CHECK_CAST for wrapped INVOKE if invoked method returns different type
if
(
castArg
.
isInsnWrap
())
{
InsnNode
wrapInsn
=
((
InsnWrapArg
)
castArg
).
getWrapInsn
();
if
(
wrapInsn
.
getType
()
==
InsnType
.
INVOKE
)
{
argType
=
((
InvokeNode
)
wrapInsn
).
getCallMth
().
getReturnType
();
}
}
ArgType
castToType
=
(
ArgType
)
((
IndexInsnNode
)
insn
).
getIndex
();
if
(
ArgType
.
isCastNeeded
(
mth
.
dex
(),
argType
,
castToType
))
{
return
null
;
}
InsnNode
insnNode
=
new
InsnNode
(
InsnType
.
MOVE
,
1
);
insnNode
.
setOffset
(
insn
.
getOffset
());
insnNode
.
setResult
(
insn
.
getResult
());
insnNode
.
addArg
(
castArg
);
return
insnNode
;
}
/**
* Simplify 'cmp' instruction in if condition
*/
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java
View file @
4e6c5cb2
...
...
@@ -55,7 +55,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
}
private
static
void
searchTryCatchDominators
(
MethodNode
mth
,
Map
<
BlockNode
,
TryCatchBlock
>
tryBlocksMap
)
{
final
Set
<
TryCatchBlock
>
tryBlocks
=
new
HashSet
<
TryCatchBlock
>();
Set
<
TryCatchBlock
>
tryBlocks
=
new
HashSet
<
TryCatchBlock
>();
// collect all try/catch blocks
for
(
BlockNode
block
:
mth
.
getBasicBlocks
())
{
CatchAttr
c
=
block
.
get
(
AType
.
CATCH_BLOCK
);
...
...
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass10.java
0 → 100644
View file @
4e6c5cb2
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
java.util.Random
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestAnonymousClass10
extends
IntegrationTest
{
public
static
class
TestCls
{
public
A
test
()
{
Random
random
=
new
Random
();
int
a2
=
random
.
nextInt
();
int
a3
=
a2
+
3
;
return
new
A
(
this
,
a2
,
a3
,
4
,
5
,
random
.
nextDouble
())
{
@Override
public
void
m
()
{
System
.
out
.
println
(
1
);
}
};
}
public
abstract
class
A
{
public
A
(
TestCls
a1
,
int
a2
,
int
a3
,
int
a4
,
int
a5
,
double
a6
)
{
}
public
abstract
void
m
();
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"return new A(this, a2, a2 + 3, 4, 5, random.nextDouble()) {"
));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
)));
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass6.java
0 → 100644
View file @
4e6c5cb2
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestAnonymousClass6
extends
IntegrationTest
{
public
static
class
TestCls
{
public
Runnable
test
(
final
double
d
)
{
return
new
Runnable
()
{
public
void
run
()
{
System
.
out
.
println
(
d
);
}
};
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"public Runnable test(final double d) {"
));
assertThat
(
code
,
containsOne
(
"return new Runnable() {"
));
assertThat
(
code
,
containsOne
(
"public void run() {"
));
assertThat
(
code
,
containsOne
(
"System.out.println(d);"
));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
)));
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass7.java
0 → 100644
View file @
4e6c5cb2
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestAnonymousClass7
extends
IntegrationTest
{
public
static
class
TestCls
{
public
static
Runnable
test
(
final
double
d
)
{
return
new
Runnable
()
{
public
void
run
()
{
System
.
out
.
println
(
d
);
}
};
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"public static Runnable test(final double d) {"
));
assertThat
(
code
,
containsOne
(
"return new Runnable() {"
));
assertThat
(
code
,
containsOne
(
"public void run() {"
));
assertThat
(
code
,
containsOne
(
"System.out.println(d);"
));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
)));
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass8.java
0 → 100644
View file @
4e6c5cb2
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestAnonymousClass8
extends
IntegrationTest
{
public
static
class
TestCls
{
public
final
double
d
=
Math
.
abs
(
4
);
public
Runnable
test
()
{
return
new
Runnable
()
{
public
void
run
()
{
System
.
out
.
println
(
d
);
}
};
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"public Runnable test() {"
));
assertThat
(
code
,
containsOne
(
"return new Runnable() {"
));
assertThat
(
code
,
containsOne
(
"public void run() {"
));
assertThat
(
code
,
containsOne
(
"this.d);"
));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
)));
}
}
jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass9.java
0 → 100644
View file @
4e6c5cb2
package
jadx
.
tests
.
integration
.
inner
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
java.util.concurrent.Callable
;
import
java.util.concurrent.FutureTask
;
import
org.junit.Test
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestAnonymousClass9
extends
IntegrationTest
{
public
static
class
TestCls
{
public
Callable
<
String
>
c
=
new
Callable
<
String
>()
{
@Override
public
String
call
()
throws
Exception
{
return
"str"
;
}
};
public
Runnable
test
()
{
return
new
FutureTask
<
String
>(
this
.
c
)
{
public
void
run
()
{
System
.
out
.
println
(
6
);
}
};
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"c = new Callable<String>() {"
));
assertThat
(
code
,
containsOne
(
"return new FutureTask<String>(this.c) {"
));
assertThat
(
code
,
not
(
containsString
(
"synthetic"
)));
}
}
jadx-core/src/test/java/jadx/tests/smali/TestConstructor.java
View file @
4e6c5cb2
...
...
@@ -17,7 +17,6 @@ public class TestConstructor extends SmaliTest {
disableCompilation
();
ClassNode
cls
=
getClassNodeFromSmali
(
"TestConstructor"
);
String
code
=
cls
.
getCode
().
toString
();
System
.
out
.
println
(
code
);
assertThat
(
code
,
containsOne
(
"new SomeObject(arg3);"
));
assertThat
(
code
,
not
(
containsString
(
"= someObject"
)));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment