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
0d94af09
Commit
0d94af09
authored
May 17, 2014
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core: improve 'if' detection with 'return' instruction
parent
4a6115ed
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
358 additions
and
175 deletions
+358
-175
Jadx.java
jadx-core/src/main/java/jadx/core/Jadx.java
+2
-0
RegionGen.java
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
+11
-10
BlockNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java
+5
-0
IContainer.java
jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java
+3
-0
InsnContainer.java
...core/src/main/java/jadx/core/dex/nodes/InsnContainer.java
+9
-0
IfRegion.java
jadx-core/src/main/java/jadx/core/dex/regions/IfRegion.java
+15
-0
LoopRegion.java
...-core/src/main/java/jadx/core/dex/regions/LoopRegion.java
+5
-0
Region.java
jadx-core/src/main/java/jadx/core/dex/regions/Region.java
+8
-9
SwitchRegion.java
...ore/src/main/java/jadx/core/dex/regions/SwitchRegion.java
+5
-0
SynchronizedRegion.java
...c/main/java/jadx/core/dex/regions/SynchronizedRegion.java
+5
-0
TernaryRegion.java
...re/src/main/java/jadx/core/dex/regions/TernaryRegion.java
+5
-0
BlockMakerVisitor.java
...c/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java
+0
-35
DepthRegionTraversal.java
.../jadx/core/dex/visitors/regions/DepthRegionTraversal.java
+4
-4
IfRegionVisitor.java
.../java/jadx/core/dex/visitors/regions/IfRegionVisitor.java
+30
-29
ProcessReturnInsns.java
...va/jadx/core/dex/visitors/regions/ProcessReturnInsns.java
+0
-81
RegionMakerVisitor.java
...va/jadx/core/dex/visitors/regions/RegionMakerVisitor.java
+0
-6
ReturnVisitor.java
...in/java/jadx/core/dex/visitors/regions/ReturnVisitor.java
+119
-0
RegionUtils.java
jadx-core/src/main/java/jadx/core/utils/RegionUtils.java
+30
-0
TestRedundantBrackets.java
.../test/java/jadx/tests/internal/TestRedundantBrackets.java
+1
-1
TestRedundantReturn.java
...rc/test/java/jadx/tests/internal/TestRedundantReturn.java
+31
-0
TestConditions8.java
.../java/jadx/tests/internal/conditions/TestConditions8.java
+70
-0
No files found.
jadx-core/src/main/java/jadx/core/Jadx.java
View file @
0d94af09
...
...
@@ -18,6 +18,7 @@ import jadx.core.dex.visitors.regions.CheckRegions;
import
jadx.core.dex.visitors.regions.IfRegionVisitor
;
import
jadx.core.dex.visitors.regions.ProcessVariables
;
import
jadx.core.dex.visitors.regions.RegionMakerVisitor
;
import
jadx.core.dex.visitors.regions.ReturnVisitor
;
import
jadx.core.dex.visitors.ssa.EliminatePhiNodes
;
import
jadx.core.dex.visitors.ssa.SSATransform
;
import
jadx.core.dex.visitors.typeinference.FinishTypeInference
;
...
...
@@ -74,6 +75,7 @@ public class Jadx {
passes
.
add
(
new
CodeShrinker
());
passes
.
add
(
new
RegionMakerVisitor
());
passes
.
add
(
new
IfRegionVisitor
());
passes
.
add
(
new
ReturnVisitor
());
passes
.
add
(
new
CodeShrinker
());
passes
.
add
(
new
SimplifyVisitor
());
...
...
jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
View file @
0d94af09
...
...
@@ -130,16 +130,17 @@ public class RegionGen extends InsnGen {
* Connect if-else-if block
*/
private
boolean
connectElseIf
(
CodeWriter
code
,
IContainer
els
)
throws
CodegenException
{
if
(
els
instanceof
Region
)
{
Region
re
=
(
Region
)
els
;
List
<
IContainer
>
subBlocks
=
re
.
getSubBlocks
();
if
(
subBlocks
.
size
()
==
1
&&
subBlocks
.
get
(
0
)
instanceof
IfRegion
)
{
IfRegion
ifRegion
=
(
IfRegion
)
subBlocks
.
get
(
0
);
if
(
ifRegion
.
contains
(
AFlag
.
ELSE_IF_CHAIN
))
{
makeIf
(
ifRegion
,
code
,
false
);
return
true
;
}
}
if
(!
els
.
contains
(
AFlag
.
ELSE_IF_CHAIN
))
{
return
false
;
}
if
(!(
els
instanceof
Region
))
{
return
false
;
}
List
<
IContainer
>
subBlocks
=
((
Region
)
els
).
getSubBlocks
();
if
(
subBlocks
.
size
()
==
1
&&
subBlocks
.
get
(
0
)
instanceof
IfRegion
)
{
makeIf
((
IfRegion
)
subBlocks
.
get
(
0
),
code
,
false
);
return
true
;
}
return
false
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java
View file @
0d94af09
...
...
@@ -197,6 +197,11 @@ public class BlockNode extends AttrNode implements IBlock {
}
@Override
public
String
baseString
()
{
return
Integer
.
toString
(
id
);
}
@Override
public
String
toString
()
{
return
"B:"
+
id
+
":"
+
InsnUtils
.
formatOffset
(
startOffset
);
}
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java
View file @
0d94af09
...
...
@@ -3,4 +3,7 @@ package jadx.core.dex.nodes;
import
jadx.core.dex.attributes.IAttributeNode
;
public
interface
IContainer
extends
IAttributeNode
{
// unique id for use in 'toString()' method
String
baseString
();
}
jadx-core/src/main/java/jadx/core/dex/nodes/InsnContainer.java
View file @
0d94af09
...
...
@@ -17,4 +17,13 @@ public class InsnContainer extends AttrNode implements IBlock {
return
insns
;
}
@Override
public
String
baseString
()
{
return
Integer
.
toString
(
insns
.
size
());
}
@Override
public
String
toString
()
{
return
"InsnContainer:"
+
insns
.
size
();
}
}
jadx-core/src/main/java/jadx/core/dex/regions/IfRegion.java
View file @
0d94af09
...
...
@@ -95,6 +95,21 @@ public final class IfRegion extends AbstractRegion {
}
@Override
public
String
baseString
()
{
if
(
ternRegion
!=
null
)
{
return
ternRegion
.
baseString
();
}
StringBuilder
sb
=
new
StringBuilder
();
if
(
thenRegion
!=
null
)
{
sb
.
append
(
thenRegion
.
baseString
());
}
if
(
elseRegion
!=
null
)
{
sb
.
append
(
elseRegion
.
baseString
());
}
return
sb
.
toString
();
}
@Override
public
String
toString
()
{
if
(
ternRegion
!=
null
)
{
return
ternRegion
.
toString
();
...
...
jadx-core/src/main/java/jadx/core/dex/regions/LoopRegion.java
View file @
0d94af09
...
...
@@ -130,6 +130,11 @@ public final class LoopRegion extends AbstractRegion {
}
@Override
public
String
baseString
()
{
return
body
.
baseString
();
}
@Override
public
String
toString
()
{
return
"LOOP"
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/regions/Region.java
View file @
0d94af09
package
jadx
.
core
.
dex
.
regions
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.IRegion
;
...
...
@@ -39,17 +38,17 @@ public final class Region extends AbstractRegion {
}
@Override
public
String
to
String
()
{
public
String
base
String
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"R:"
);
sb
.
append
(
blocks
.
size
());
if
(
blocks
.
size
()
!=
0
)
{
for
(
IContainer
cont
:
blocks
)
{
if
(
cont
instanceof
BlockNode
)
{
sb
.
append
(((
BlockNode
)
cont
).
getId
());
}
}
for
(
IContainer
cont
:
blocks
)
{
sb
.
append
(
cont
.
baseString
());
}
return
sb
.
toString
();
}
@Override
public
String
toString
()
{
return
"R:"
+
baseString
();
}
}
jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java
View file @
0d94af09
...
...
@@ -60,6 +60,11 @@ public final class SwitchRegion extends AbstractRegion {
}
@Override
public
String
baseString
()
{
return
header
.
baseString
();
}
@Override
public
String
toString
()
{
return
"Switch: "
+
cases
.
size
()
+
", default: "
+
defCase
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/regions/SynchronizedRegion.java
View file @
0d94af09
...
...
@@ -37,6 +37,11 @@ public final class SynchronizedRegion extends AbstractRegion {
}
@Override
public
String
baseString
()
{
return
Integer
.
toHexString
(
enterInsn
.
getOffset
());
}
@Override
public
String
toString
()
{
return
"Synchronized:"
+
region
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/regions/TernaryRegion.java
View file @
0d94af09
...
...
@@ -26,6 +26,11 @@ public final class TernaryRegion extends AbstractRegion {
}
@Override
public
String
baseString
()
{
return
container
.
baseString
();
}
@Override
public
String
toString
()
{
return
"TERN:"
+
container
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/BlockMakerVisitor.java
View file @
0d94af09
...
...
@@ -6,7 +6,6 @@ import jadx.core.dex.attributes.nodes.JumpInfo;
import
jadx.core.dex.attributes.nodes.LoopInfo
;
import
jadx.core.dex.instructions.IfNode
;
import
jadx.core.dex.instructions.InsnType
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.nodes.BlockNode
;
...
...
@@ -415,9 +414,6 @@ public class BlockMakerVisitor extends AbstractVisitor {
if
(
splitReturn
(
mth
))
{
return
true
;
}
if
(
mergeReturn
(
mth
))
{
return
true
;
}
return
false
;
}
...
...
@@ -431,37 +427,6 @@ public class BlockMakerVisitor extends AbstractVisitor {
}
/**
* Merge return blocks for void methods
*/
private
static
boolean
mergeReturn
(
MethodNode
mth
)
{
if
(
mth
.
getExitBlocks
().
size
()
==
1
||
!
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
))
{
return
false
;
}
for
(
BlockNode
exitBlock
:
mth
.
getExitBlocks
())
{
List
<
BlockNode
>
preds
=
exitBlock
.
getPredecessors
();
if
(
preds
.
size
()
!=
1
)
{
continue
;
}
BlockNode
pred
=
preds
.
get
(
0
);
for
(
BlockNode
otherExitBlock
:
mth
.
getExitBlocks
())
{
if
(
exitBlock
!=
otherExitBlock
&&
otherExitBlock
.
isDominator
(
pred
)
&&
otherExitBlock
.
getPredecessors
().
size
()
==
1
)
{
BlockNode
otherPred
=
otherExitBlock
.
getPredecessors
().
get
(
0
);
if
(
pred
!=
otherPred
)
{
// merge
removeConnection
(
otherPred
,
otherExitBlock
);
connect
(
otherPred
,
exitBlock
);
cleanExitNodes
(
mth
);
return
true
;
}
}
}
}
return
false
;
}
/**
* Splice return block if several predecessors presents
*/
private
static
boolean
splitReturn
(
MethodNode
mth
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraversal.java
View file @
0d94af09
...
...
@@ -16,7 +16,7 @@ public class DepthRegionTraversal {
}
public
static
void
traverseAll
(
MethodNode
mth
,
IRegionVisitor
visitor
)
{
traverse
(
mth
,
visitor
);
traverse
Internal
(
mth
,
visitor
,
mth
.
getRegion
()
);
for
(
ExceptionHandler
h
:
mth
.
getExceptionHandlers
())
{
traverseInternal
(
mth
,
visitor
,
h
.
getHandlerRegion
());
}
...
...
@@ -25,7 +25,7 @@ public class DepthRegionTraversal {
public
static
void
traverseAllIterative
(
MethodNode
mth
,
IRegionIterativeVisitor
visitor
)
{
boolean
repeat
;
do
{
repeat
=
traverseAllIterativeIntern
(
mth
,
visitor
);
repeat
=
traverseAllIterativeIntern
al
(
mth
,
visitor
);
}
while
(
repeat
);
}
...
...
@@ -42,7 +42,7 @@ public class DepthRegionTraversal {
}
}
private
static
boolean
traverseAllIterativeIntern
(
MethodNode
mth
,
IRegionIterativeVisitor
visitor
)
{
private
static
boolean
traverseAllIterativeIntern
al
(
MethodNode
mth
,
IRegionIterativeVisitor
visitor
)
{
if
(
traverseIterativeInternal
(
mth
,
visitor
,
mth
.
getRegion
()))
{
return
true
;
}
...
...
@@ -54,7 +54,7 @@ public class DepthRegionTraversal {
return
false
;
}
p
ublic
static
boolean
traverseIterativeInternal
(
MethodNode
mth
,
IRegionIterativeVisitor
visitor
,
IContainer
container
)
{
p
rivate
static
boolean
traverseIterativeInternal
(
MethodNode
mth
,
IRegionIterativeVisitor
visitor
,
IContainer
container
)
{
if
(
container
instanceof
IRegion
)
{
IRegion
region
=
(
IRegion
)
container
;
if
(
visitor
.
visitRegion
(
mth
,
region
))
{
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java
View file @
0d94af09
...
...
@@ -57,24 +57,45 @@ public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor,
if
(
ifRegion
.
simplifyCondition
())
{
IfCondition
condition
=
ifRegion
.
getCondition
();
if
(
condition
.
getMode
()
==
IfCondition
.
Mode
.
NOT
)
{
tryI
nvertIfRegion
(
ifRegion
);
i
nvertIfRegion
(
ifRegion
);
}
}
if
(
RegionUtils
.
isEmpty
(
ifRegion
.
getThenRegion
()))
{
tryInvertIfRegion
(
ifRegion
);
if
(
RegionUtils
.
isEmpty
(
ifRegion
.
getThenRegion
())
||
hasSimpleReturnBlock
(
ifRegion
.
getThenRegion
()))
{
invertIfRegion
(
ifRegion
);
}
}
private
static
void
moveReturnToThenBlock
(
MethodNode
mth
,
IfRegion
ifRegion
)
{
if
(!
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
)
&&
hasSimpleReturnBlock
(
ifRegion
.
getElseRegion
())
&&
!
hasSimpleReturnBlock
(
ifRegion
.
getThenRegion
()))
{
tryInvertIfRegion
(
ifRegion
);
/*&& insnsCount(ifRegion.getThenRegion()) < 2*/
)
{
invertIfRegion
(
ifRegion
);
}
}
/**
* Mark if-else-if chains
*/
private
static
void
markElseIfChains
(
IfRegion
ifRegion
)
{
if
(
hasSimpleReturnBlock
(
ifRegion
.
getThenRegion
()))
{
return
;
}
IContainer
elsRegion
=
ifRegion
.
getElseRegion
();
if
(
elsRegion
instanceof
Region
)
{
List
<
IContainer
>
subBlocks
=
((
Region
)
elsRegion
).
getSubBlocks
();
if
(
subBlocks
.
size
()
==
1
&&
subBlocks
.
get
(
0
)
instanceof
IfRegion
)
{
subBlocks
.
get
(
0
).
add
(
AFlag
.
ELSE_IF_CHAIN
);
elsRegion
.
add
(
AFlag
.
ELSE_IF_CHAIN
);
}
}
}
private
static
boolean
removeRedundantElseBlock
(
IfRegion
ifRegion
)
{
if
(
ifRegion
.
getElseRegion
()
!=
null
&&
hasSimpleReturnBlock
(
ifRegion
.
getThenRegion
()))
{
if
(
ifRegion
.
getElseRegion
()
!=
null
&&
!
ifRegion
.
contains
(
AFlag
.
ELSE_IF_CHAIN
)
&&
!
ifRegion
.
getElseRegion
().
contains
(
AFlag
.
ELSE_IF_CHAIN
)
&&
RegionUtils
.
hasExitBlock
(
ifRegion
.
getThenRegion
()))
{
IRegion
parent
=
ifRegion
.
getParent
();
Region
newRegion
=
new
Region
(
parent
);
if
(
parent
.
replaceSubBlock
(
ifRegion
,
newRegion
))
{
...
...
@@ -87,26 +108,9 @@ public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor,
return
false
;
}
/**
* Mark if-else-if chains
*/
private
static
void
markElseIfChains
(
IfRegion
ifRegion
)
{
IContainer
elsRegion
=
ifRegion
.
getElseRegion
();
if
(
elsRegion
!=
null
)
{
if
(
elsRegion
instanceof
IfRegion
)
{
elsRegion
.
add
(
AFlag
.
ELSE_IF_CHAIN
);
}
else
if
(
elsRegion
instanceof
Region
)
{
List
<
IContainer
>
subBlocks
=
((
Region
)
elsRegion
).
getSubBlocks
();
if
(
subBlocks
.
size
()
==
1
&&
subBlocks
.
get
(
0
)
instanceof
IfRegion
)
{
subBlocks
.
get
(
0
).
add
(
AFlag
.
ELSE_IF_CHAIN
);
}
}
}
}
private
static
void
tryInvertIfRegion
(
IfRegion
ifRegion
)
{
private
static
void
invertIfRegion
(
IfRegion
ifRegion
)
{
IContainer
elseRegion
=
ifRegion
.
getElseRegion
();
if
(
elseRegion
!=
null
&&
RegionUtils
.
notEmpty
(
elseRegion
)
)
{
if
(
elseRegion
!=
null
)
{
ifRegion
.
invert
();
}
}
...
...
@@ -120,10 +124,7 @@ public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor,
}
if
(
region
instanceof
IRegion
)
{
List
<
IContainer
>
subBlocks
=
((
IRegion
)
region
).
getSubBlocks
();
if
(
subBlocks
.
size
()
==
1
&&
subBlocks
.
get
(
0
).
contains
(
AFlag
.
RETURN
))
{
return
true
;
}
return
subBlocks
.
size
()
==
1
&&
subBlocks
.
get
(
0
).
contains
(
AFlag
.
RETURN
);
}
return
false
;
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessReturnInsns.java
deleted
100644 → 0
View file @
4a6115ed
package
jadx
.
core
.
dex
.
visitors
.
regions
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.IBlock
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.IRegion
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.regions.IfRegion
;
import
jadx.core.dex.regions.LoopRegion
;
import
jadx.core.dex.regions.SwitchRegion
;
import
jadx.core.utils.RegionUtils
;
import
java.util.List
;
import
java.util.ListIterator
;
/**
* Remove unnecessary return instructions for void methods
*/
public
class
ProcessReturnInsns
extends
TracedRegionVisitor
{
@Override
public
void
processBlockTraced
(
MethodNode
mth
,
IBlock
container
,
IRegion
currentRegion
)
{
if
(
container
.
getClass
()
!=
BlockNode
.
class
)
{
return
;
}
BlockNode
block
=
(
BlockNode
)
container
;
if
(
block
.
contains
(
AFlag
.
RETURN
))
{
List
<
InsnNode
>
insns
=
block
.
getInstructions
();
if
(
insns
.
size
()
==
1
&&
blockNotInLoop
(
mth
,
block
)
&&
noTrailInstructions
(
block
))
{
insns
.
remove
(
insns
.
size
()
-
1
);
block
.
remove
(
AFlag
.
RETURN
);
}
}
}
private
boolean
blockNotInLoop
(
MethodNode
mth
,
BlockNode
block
)
{
if
(
mth
.
getLoopForBlock
(
block
)
!=
null
)
{
return
false
;
}
for
(
IRegion
region
:
regionStack
)
{
if
(
region
.
getClass
()
==
LoopRegion
.
class
)
{
return
false
;
}
}
return
true
;
}
/**
* Check that there no code after this block in regions structure
*/
private
boolean
noTrailInstructions
(
BlockNode
block
)
{
IContainer
curContainer
=
block
;
for
(
IRegion
region
:
regionStack
)
{
// ignore paths on other branches
if
(
region
instanceof
IfRegion
||
region
instanceof
SwitchRegion
)
{
curContainer
=
region
;
continue
;
}
List
<
IContainer
>
subBlocks
=
region
.
getSubBlocks
();
if
(!
subBlocks
.
isEmpty
())
{
ListIterator
<
IContainer
>
itSubBlock
=
subBlocks
.
listIterator
(
subBlocks
.
size
());
while
(
itSubBlock
.
hasPrevious
())
{
IContainer
subBlock
=
itSubBlock
.
previous
();
if
(
subBlock
==
curContainer
)
{
break
;
}
else
if
(!
subBlock
.
contains
(
AFlag
.
RETURN
)
&&
RegionUtils
.
notEmpty
(
subBlock
))
{
return
false
;
}
}
}
curContainer
=
region
;
}
return
true
;
}
}
jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMakerVisitor.java
View file @
0d94af09
package
jadx
.
core
.
dex
.
visitors
.
regions
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.IRegion
;
import
jadx.core.dex.nodes.InsnNode
;
...
...
@@ -64,11 +63,6 @@ public class RegionMakerVisitor extends AbstractVisitor {
CleanRegions
.
process
(
mth
);
// remove useless returns in void methods
if
(
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
))
{
DepthRegionTraversal
.
traverseAll
(
mth
,
new
ProcessReturnInsns
());
}
if
(
mth
.
getAccessFlags
().
isSynchronized
())
{
removeSynchronized
(
mth
);
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/regions/ReturnVisitor.java
0 → 100644
View file @
0d94af09
package
jadx
.
core
.
dex
.
visitors
.
regions
;
import
jadx.core.dex.attributes.AFlag
;
import
jadx.core.dex.instructions.args.ArgType
;
import
jadx.core.dex.nodes.BlockNode
;
import
jadx.core.dex.nodes.IBlock
;
import
jadx.core.dex.nodes.IContainer
;
import
jadx.core.dex.nodes.IRegion
;
import
jadx.core.dex.nodes.InsnNode
;
import
jadx.core.dex.nodes.MethodNode
;
import
jadx.core.dex.regions.IfRegion
;
import
jadx.core.dex.regions.LoopRegion
;
import
jadx.core.dex.regions.SwitchRegion
;
import
jadx.core.dex.visitors.AbstractVisitor
;
import
jadx.core.utils.RegionUtils
;
import
jadx.core.utils.exceptions.JadxException
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.ListIterator
;
import
java.util.Set
;
/**
* Remove unnecessary return instructions for void methods
*/
public
class
ReturnVisitor
extends
AbstractVisitor
{
@Override
public
void
visit
(
MethodNode
mth
)
throws
JadxException
{
// remove useless returns in void methods
if
(
mth
.
getReturnType
().
equals
(
ArgType
.
VOID
))
{
DepthRegionTraversal
.
traverseAll
(
mth
,
new
Process
());
}
}
private
static
final
class
Process
extends
TracedRegionVisitor
{
@Override
public
void
processBlockTraced
(
MethodNode
mth
,
IBlock
container
,
IRegion
currentRegion
)
{
if
(
container
.
getClass
()
!=
BlockNode
.
class
)
{
return
;
}
BlockNode
block
=
(
BlockNode
)
container
;
if
(
block
.
contains
(
AFlag
.
RETURN
))
{
List
<
InsnNode
>
insns
=
block
.
getInstructions
();
if
(
insns
.
size
()
==
1
&&
blockNotInLoop
(
mth
,
block
)
&&
noTrailInstructions
(
block
))
{
insns
.
remove
(
insns
.
size
()
-
1
);
block
.
remove
(
AFlag
.
RETURN
);
}
}
}
private
boolean
blockNotInLoop
(
MethodNode
mth
,
BlockNode
block
)
{
if
(
mth
.
getLoopsCount
()
==
0
)
{
return
true
;
}
if
(
mth
.
getLoopForBlock
(
block
)
!=
null
)
{
return
false
;
}
for
(
IRegion
region
:
regionStack
)
{
if
(
region
.
getClass
()
==
LoopRegion
.
class
)
{
return
false
;
}
}
return
true
;
}
/**
* Check that there are no code after this block in regions structure
*/
private
boolean
noTrailInstructions
(
BlockNode
block
)
{
IContainer
curContainer
=
block
;
for
(
IRegion
region
:
regionStack
)
{
// ignore paths on other branches
if
(
region
instanceof
IfRegion
||
region
instanceof
SwitchRegion
)
{
curContainer
=
region
;
continue
;
}
List
<
IContainer
>
subBlocks
=
region
.
getSubBlocks
();
if
(!
subBlocks
.
isEmpty
())
{
ListIterator
<
IContainer
>
itSubBlock
=
subBlocks
.
listIterator
(
subBlocks
.
size
());
while
(
itSubBlock
.
hasPrevious
())
{
IContainer
subBlock
=
itSubBlock
.
previous
();
if
(
subBlock
==
curContainer
)
{
break
;
}
else
if
(
notEmpty
(
subBlock
))
{
return
false
;
}
}
}
curContainer
=
region
;
}
return
true
;
}
private
static
boolean
notEmpty
(
IContainer
subBlock
)
{
if
(
subBlock
.
contains
(
AFlag
.
RETURN
))
{
return
false
;
}
int
insnCount
=
RegionUtils
.
insnsCount
(
subBlock
);
if
(
insnCount
>
1
)
{
return
true
;
}
if
(
insnCount
==
1
)
{
// don't count one 'return' instruction (it will be removed later)
Set
<
BlockNode
>
blocks
=
new
HashSet
<
BlockNode
>();
RegionUtils
.
getAllRegionBlocks
(
subBlock
,
blocks
);
for
(
BlockNode
node
:
blocks
)
{
if
(!
node
.
contains
(
AFlag
.
RETURN
)
&&
!
node
.
getInstructions
().
isEmpty
())
{
return
true
;
}
}
}
return
false
;
}
}
}
jadx-core/src/main/java/jadx/core/utils/RegionUtils.java
View file @
0d94af09
...
...
@@ -32,6 +32,36 @@ public class RegionUtils {
}
}
/**
* Return true if last block in region has no successors
*/
public
static
boolean
hasExitBlock
(
IContainer
container
)
{
if
(
container
instanceof
BlockNode
)
{
return
((
BlockNode
)
container
).
getSuccessors
().
size
()
==
0
;
}
else
if
(
container
instanceof
IRegion
)
{
List
<
IContainer
>
blocks
=
((
IRegion
)
container
).
getSubBlocks
();
return
!
blocks
.
isEmpty
()
&&
hasExitBlock
(
blocks
.
get
(
blocks
.
size
()
-
1
));
}
else
{
throw
new
JadxRuntimeException
(
"Unknown container type: "
+
container
.
getClass
());
}
}
public
static
int
insnsCount
(
IContainer
container
)
{
if
(
container
instanceof
BlockNode
)
{
return
((
BlockNode
)
container
).
getInstructions
().
size
();
}
else
if
(
container
instanceof
IRegion
)
{
IRegion
region
=
(
IRegion
)
container
;
int
count
=
0
;
for
(
IContainer
block
:
region
.
getSubBlocks
())
{
count
+=
insnsCount
(
block
);
}
return
count
;
}
else
{
throw
new
JadxRuntimeException
(
"Unknown container type: "
+
container
.
getClass
());
}
}
public
static
boolean
isEmpty
(
IContainer
container
)
{
return
!
notEmpty
(
container
);
}
...
...
jadx-core/src/test/java/jadx/tests/internal/TestRedundantBrackets.java
View file @
0d94af09
...
...
@@ -53,7 +53,7 @@ public class TestRedundantBrackets extends InternalJadxTest {
assertThat
(
code
,
containsString
(
"return obj instanceof String ? ((String) obj).length() : 0;"
));
assertThat
(
code
,
containsString
(
"if (a + b < 10)"
));
assertThat
(
code
,
containsString
(
"if ((a & b) != 0)"
));
//
assertThat(code, containsString("if ((a & b) != 0)"));
assertThat
(
code
,
containsString
(
"if (num == 4 || num == 6 || num == 8 || num == 10)"
));
assertThat
(
code
,
containsString
(
"a[1] = n * 2;"
));
...
...
jadx-core/src/test/java/jadx/tests/internal/TestRedundantReturn.java
0 → 100644
View file @
0d94af09
package
jadx
.
tests
.
internal
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
fail
;
public
class
TestRedundantReturn
extends
InternalJadxTest
{
public
static
class
TestCls
{
public
void
test
(
int
num
)
{
if
(
num
==
4
)
{
fail
();
}
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
System
.
out
.
println
(
code
);
assertThat
(
code
,
not
(
containsString
(
"return;"
)));
}
}
jadx-core/src/test/java/jadx/tests/internal/conditions/TestConditions8.java
0 → 100644
View file @
0d94af09
package
jadx
.
tests
.
internal
.
conditions
;
import
jadx.api.InternalJadxTest
;
import
jadx.core.dex.nodes.ClassNode
;
import
org.junit.Test
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
junit
.
Assert
.
assertThat
;
public
class
TestConditions8
extends
InternalJadxTest
{
public
static
class
TestCls
{
private
TestCls
pager
;
private
TestCls
listView
;
public
void
test
(
TestCls
view
,
int
firstVisibleItem
,
int
visibleItemCount
,
int
totalItemCount
)
{
if
(!
isUsable
())
{
return
;
}
if
(!
pager
.
hasMore
())
{
return
;
}
if
(
getLoaderManager
().
hasRunningLoaders
())
{
return
;
}
if
(
listView
!=
null
&&
listView
.
getLastVisiblePosition
()
>=
pager
.
size
())
{
showMore
();
}
}
private
void
showMore
()
{
}
private
int
size
()
{
return
0
;
}
private
int
getLastVisiblePosition
()
{
return
0
;
}
private
boolean
hasRunningLoaders
()
{
return
false
;
}
private
TestCls
getLoaderManager
()
{
return
null
;
}
private
boolean
hasMore
()
{
return
false
;
}
private
boolean
isUsable
()
{
return
false
;
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
System
.
out
.
println
(
code
);
assertThat
(
code
,
containsString
(
"showMore();"
));
}
}
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