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
8410e625
Commit
8410e625
authored
Jul 05, 2019
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: force one branch ternary in constructors (#685)
parent
533b686e
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
118 additions
and
1 deletion
+118
-1
TernaryMod.java
.../main/java/jadx/core/dex/visitors/regions/TernaryMod.java
+67
-1
TestTernaryOneBranchInConstructor.java
...gration/conditions/TestTernaryOneBranchInConstructor.java
+51
-0
No files found.
jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java
View file @
8410e625
...
...
@@ -21,6 +21,7 @@ import jadx.core.dex.regions.Region;
import
jadx.core.dex.regions.conditions.IfRegion
;
import
jadx.core.dex.visitors.shrink.CodeShrinkVisitor
;
import
jadx.core.utils.InsnList
;
import
jadx.core.utils.InsnRemover
;
/**
* Convert 'if' to ternary operation
...
...
@@ -41,7 +42,14 @@ public class TernaryMod implements IRegionIterativeVisitor {
}
IContainer
thenRegion
=
ifRegion
.
getThenRegion
();
IContainer
elseRegion
=
ifRegion
.
getElseRegion
();
if
(
thenRegion
==
null
||
elseRegion
==
null
)
{
if
(
thenRegion
==
null
)
{
return
false
;
}
if
(
elseRegion
==
null
)
{
if
(
mth
.
isConstructor
())
{
// force ternary conversion to inline all code in 'super' or 'this' calls
return
processOneBranchTernary
(
mth
,
ifRegion
);
}
return
false
;
}
BlockNode
tb
=
getTernaryInsnBlock
(
thenRegion
);
...
...
@@ -219,4 +227,62 @@ public class TernaryMod implements IRegionIterativeVisitor {
}
return
false
;
}
/**
* Convert one variable change with only 'then' branch:
* 'if (c) {r = a;}' to 'r = c ? a : r'
* Also convert only if 'r' used only once
*/
private
static
boolean
processOneBranchTernary
(
MethodNode
mth
,
IfRegion
ifRegion
)
{
IContainer
thenRegion
=
ifRegion
.
getThenRegion
();
BlockNode
block
=
getTernaryInsnBlock
(
thenRegion
);
if
(
block
!=
null
)
{
InsnNode
insn
=
block
.
getInstructions
().
get
(
0
);
RegisterArg
result
=
insn
.
getResult
();
if
(
result
!=
null
)
{
replaceWithTernary
(
mth
,
ifRegion
,
block
,
insn
);
}
}
return
false
;
}
private
static
void
replaceWithTernary
(
MethodNode
mth
,
IfRegion
ifRegion
,
BlockNode
block
,
InsnNode
insn
)
{
BlockNode
header
=
ifRegion
.
getConditionBlocks
().
get
(
0
);
if
(!
ifRegion
.
getParent
().
replaceSubBlock
(
ifRegion
,
header
))
{
return
;
}
RegisterArg
resArg
=
insn
.
getResult
();
if
(
resArg
.
getSVar
().
getUseList
().
size
()
!=
1
)
{
return
;
}
PhiInsn
phiInsn
=
resArg
.
getSVar
().
getOnlyOneUseInPhi
();
if
(
phiInsn
==
null
||
phiInsn
.
getArgsCount
()
!=
2
)
{
return
;
}
RegisterArg
otherArg
=
null
;
for
(
InsnArg
arg
:
phiInsn
.
getArguments
())
{
if
(
arg
!=
resArg
&&
arg
instanceof
RegisterArg
)
{
otherArg
=
(
RegisterArg
)
arg
;
break
;
}
}
if
(
otherArg
==
null
)
{
return
;
}
// all checks passed
InsnList
.
remove
(
block
,
insn
);
TernaryInsn
ternInsn
=
new
TernaryInsn
(
ifRegion
.
getCondition
(),
phiInsn
.
getResult
(),
InsnArg
.
wrapArg
(
insn
),
otherArg
);
ternInsn
.
setSourceLine
(
insn
.
getSourceLine
());
InsnRemover
.
unbindInsn
(
mth
,
phiInsn
);
header
.
getInstructions
().
clear
();
header
.
getInstructions
().
add
(
ternInsn
);
clearConditionBlocks
(
ifRegion
.
getConditionBlocks
(),
header
);
// shrink method again
CodeShrinkVisitor
.
shrinkMethod
(
mth
);
}
}
jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernaryOneBranchInConstructor.java
0 → 100644
View file @
8410e625
package
jadx
.
tests
.
integration
.
conditions
;
import
org.junit.jupiter.api.Test
;
import
jadx.core.dex.nodes.ClassNode
;
import
jadx.tests.api.IntegrationTest
;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
public
class
TestTernaryOneBranchInConstructor
extends
IntegrationTest
{
public
static
class
TestCls
{
public
TestCls
(
String
str
,
int
i
)
{
this
(
str
==
null
?
0
:
i
);
}
public
TestCls
(
int
i
)
{
}
}
@Test
public
void
test
()
{
ClassNode
cls
=
getClassNode
(
TestCls
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"this(str == null ? 0 : i);"
));
assertThat
(
code
,
not
(
containsString
(
"//"
)));
}
public
static
class
TestCls2
{
public
TestCls2
(
String
str
,
int
i
)
{
this
(
i
==
1
?
str
:
""
,
i
==
0
?
""
:
str
);
}
public
TestCls2
(
String
a
,
String
b
)
{
}
}
@Test
public
void
test2
()
{
noDebugInfo
();
ClassNode
cls
=
getClassNode
(
TestCls2
.
class
);
String
code
=
cls
.
getCode
().
toString
();
assertThat
(
code
,
containsOne
(
"this(i == 1 ? str : \"\", i == 0 ? \"\" : str);"
));
assertThat
(
code
,
not
(
containsString
(
"//"
)));
}
}
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