Skip to content

Commit 15b6309

Browse files
authored
fix: support "fall-through to default" case in switch-over-string (PR #2338)
1 parent 417bb7a commit 15b6309

File tree

3 files changed

+78
-25
lines changed

3 files changed

+78
-25
lines changed

jadx-core/src/main/java/jadx/core/dex/regions/SwitchRegion.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ public void addCase(List<Object> keysList, IContainer c) {
5858
cases.add(new CaseInfo(keysList, c));
5959
}
6060

61-
public void addDefaultCase(IContainer c) {
62-
if (c != null) {
63-
cases.add(new CaseInfo(Collections.singletonList(DEFAULT_CASE_KEY), c));
64-
}
65-
}
66-
6761
public List<CaseInfo> getCases() {
6862
return cases;
6963
}

jadx-core/src/main/java/jadx/core/dex/visitors/regions/SwitchOverStringVisitor.java

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,9 @@ private boolean restoreSwitchOverString(MethodNode mth, SwitchRegion switchRegio
106106
// all checks passed, replace with new switch
107107
IRegion parentRegion = switchRegion.getParent();
108108
SwitchRegion replaceRegion = new SwitchRegion(parentRegion, switchRegion.getHeader());
109-
for (CaseData caseData : switchData.getCases()) {
110-
replaceRegion.addCase(Collections.unmodifiableList(caseData.getStrValues()), caseData.getCode());
109+
for (SwitchRegion.CaseInfo caseInfo : switchData.getNewCases()) {
110+
replaceRegion.addCase(Collections.unmodifiableList(caseInfo.getKeys()), caseInfo.getContainer());
111111
}
112-
replaceRegion.addDefaultCase(switchData.getDefaultCode());
113112
if (!parentRegion.replaceSubBlock(switchRegion, replaceRegion)) {
114113
mth.addWarnComment("Failed to restore switch over string. Please report as a decompilation issue");
115114
return false;
@@ -216,36 +215,53 @@ private boolean mergeWithCode(SwitchData switchData) {
216215
block -> switchData.getToRemove().add(block));
217216
}
218217

219-
IContainer defaultContainer = null;
218+
final var newCases = new ArrayList<SwitchRegion.CaseInfo>();
220219
for (SwitchRegion.CaseInfo caseInfo : codeSwitch.getCases()) {
221-
CaseData prevCase = null;
220+
SwitchRegion.CaseInfo newCase = null;
222221
for (Object key : caseInfo.getKeys()) {
223222
final Integer intKey = unwrapIntKey(key);
224223
if (intKey != null) {
225-
CaseData caseData = casesMap.get(intKey);
224+
final var caseData = casesMap.remove(intKey);
226225
if (caseData == null) {
227226
return false;
228227
}
229-
if (prevCase == null) {
230-
caseData.setCode(caseInfo.getContainer());
231-
prevCase = caseData;
228+
if (newCase == null) {
229+
final List<Object> keys = new ArrayList<>(caseData.getStrValues());
230+
newCase = new SwitchRegion.CaseInfo(keys, caseInfo.getContainer());
232231
} else {
233232
// merge cases
234-
prevCase.getStrValues().addAll(caseData.getStrValues());
235-
caseData.setCodeNum(-1);
233+
newCase.getKeys().addAll(caseData.getStrValues());
236234
}
237235
} else if (key == SwitchRegion.DEFAULT_CASE_KEY) {
238-
defaultContainer = caseInfo.getContainer();
236+
final var iterator = casesMap.entrySet().iterator();
237+
while (iterator.hasNext()) {
238+
final var caseData = iterator.next().getValue();
239+
if (newCase == null) {
240+
final List<Object> keys = new ArrayList<>(caseData.getStrValues());
241+
newCase = new SwitchRegion.CaseInfo(keys, caseInfo.getContainer());
242+
} else {
243+
// merge cases
244+
newCase.getKeys().addAll(caseData.getStrValues());
245+
}
246+
247+
iterator.remove();
248+
}
249+
250+
if (newCase == null) {
251+
newCase = new SwitchRegion.CaseInfo(new ArrayList<>(), caseInfo.getContainer());
252+
}
253+
254+
newCase.getKeys().add(SwitchRegion.DEFAULT_CASE_KEY);
239255
} else {
240256
return false;
241257
}
242258
}
259+
newCases.add(newCase);
243260
}
244-
cases.removeIf(c -> c.getCodeNum() == -1);
245261

246-
switchData.setDefaultCode(defaultContainer);
247262
switchData.setCodeSwitch(codeSwitch);
248263
switchData.setNumArg(numArg);
264+
switchData.setNewCases(newCases);
249265
return true;
250266
}
251267

@@ -367,7 +383,7 @@ private static final class SwitchData {
367383
private final List<IAttributeNode> toRemove = new ArrayList<>();
368384
private Map<InsnNode, String> strEqInsns;
369385
private List<CaseData> cases;
370-
private IContainer defaultCode;
386+
private List<SwitchRegion.CaseInfo> newCases;
371387
private SwitchRegion codeSwitch;
372388
private RegisterArg numArg;
373389

@@ -384,12 +400,12 @@ public void setCases(List<CaseData> cases) {
384400
this.cases = cases;
385401
}
386402

387-
public IContainer getDefaultCode() {
388-
return defaultCode;
403+
public List<SwitchRegion.CaseInfo> getNewCases() {
404+
return newCases;
389405
}
390406

391-
public void setDefaultCode(IContainer defaultCode) {
392-
this.defaultCode = defaultCode;
407+
public void setNewCases(List<SwitchRegion.CaseInfo> cases) {
408+
this.newCases = cases;
393409
}
394410

395411
public MethodNode getMth() {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package jadx.tests.integration.switches;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import jadx.tests.api.IntegrationTest;
6+
7+
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
8+
9+
public class TestSwitchOverStrings2 extends IntegrationTest {
10+
11+
public static class TestCls {
12+
13+
public int test(String str) {
14+
switch (str) {
15+
case "branch1":
16+
case "branch2":
17+
return 1;
18+
case "branch3":
19+
case "branch4":
20+
default:
21+
return 0;
22+
}
23+
}
24+
25+
public void check() {
26+
assertThat(test("branch1")).isEqualTo(1);
27+
assertThat(test("branch2")).isEqualTo(1);
28+
assertThat(test("branch3")).isEqualTo(0);
29+
assertThat(test("branch4")).isEqualTo(0);
30+
assertThat(test("other")).isEqualTo(0);
31+
assertThat(test("other2")).isEqualTo(0);
32+
}
33+
}
34+
35+
@Test
36+
public void test() {
37+
assertThat(getClassNode(TestCls.class))
38+
.code()
39+
.countString(4, "case ")
40+
.countString(1, "default:")
41+
.countString(2, "return ");
42+
}
43+
}

0 commit comments

Comments
 (0)