Skip to content

Commit cbf6c4f

Browse files
committed
fixup! Add getControlFlowGraph() to relevant node impls
1 parent 76920d4 commit cbf6c4f

File tree

4 files changed

+37
-10
lines changed

4 files changed

+37
-10
lines changed

delphi-frontend/src/main/java/au/com/integradev/delphi/cfg/ControlFlowGraphVisitor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,14 +361,14 @@ public ControlFlowGraphBuilder visit(CaseStatementNode node, ControlFlowGraphBui
361361

362362
Set<ProtoBlock> caseSuccessors = new HashSet<>();
363363

364+
// If none of the case arms match, it will either skip the block, or
365+
// fallthrough to an `else` block
366+
ProtoBlock fallthrough = after;
364367
// Else
365368
if (node.getElseBlockNode() != null) {
366369
builder.addBlockBefore(after);
367370
build(node.getElseBlockNode().getStatementList(), builder);
368-
caseSuccessors.add(builder.getCurrentBlock());
369-
} else {
370-
// If there is no `else` block the statement can be jumped
371-
caseSuccessors.add(after);
371+
fallthrough = builder.getCurrentBlock();
372372
}
373373

374374
// Cases
@@ -382,7 +382,7 @@ public ControlFlowGraphBuilder visit(CaseStatementNode node, ControlFlowGraphBui
382382
caseSuccessors.add(builder.getCurrentBlock());
383383
}
384384

385-
caseBlock.update(ProtoBlockFactory.cases(node, caseSuccessors));
385+
caseBlock.update(ProtoBlockFactory.cases(node, caseSuccessors, fallthrough));
386386
builder.setCurrentBlock(conditionBlock);
387387
return builder;
388388
}

delphi-frontend/src/main/java/au/com/integradev/delphi/cfg/api/Cases.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ public interface Cases extends Block, Terminated {
2929
*/
3030
Set<Block> getCaseSuccessors();
3131

32+
/**
33+
* Either the fallthrough {@code else} block or the next block in the {@link ControlFlowGraph}
34+
*
35+
* @return the fallthrough successor
36+
*/
37+
Block getFallthroughSuccessor();
38+
3239
@Override
3340
default Set<Block> getSuccessors() {
3441
return getCaseSuccessors();

delphi-frontend/src/main/java/au/com/integradev/delphi/cfg/block/ProtoBlockFactory.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,16 @@ public static ProtoBlock withExceptions(ProtoBlock successor, Set<ProtoBlock> ex
8686
exceptions.stream().map(blocks::get).collect(Collectors.toSet())));
8787
}
8888

89-
public static ProtoBlock cases(DelphiNode terminator, Set<ProtoBlock> cases) {
89+
public static ProtoBlock cases(
90+
DelphiNode terminator, Set<ProtoBlock> cases, ProtoBlock fallthrough) {
9091
return new ProtoBlock(
9192
CasesImpl::new,
9293
(blocks, block) ->
9394
((CasesImpl) block)
94-
.setData(terminator, cases.stream().map(blocks::get).collect(Collectors.toSet())));
95+
.setData(
96+
terminator,
97+
cases.stream().map(blocks::get).collect(Collectors.toSet()),
98+
blocks.get(fallthrough)));
9599
}
96100

97101
private static String getBlocksString(Collection<Block> block) {
@@ -144,21 +148,28 @@ public String getDescription() {
144148
static class CasesImpl extends BlockImpl implements Cases {
145149
private Terminator terminator;
146150
private Set<Block> cases;
151+
private Block fallthrough;
147152

148153
public CasesImpl(List<DelphiNode> elements) {
149154
super(elements);
150155
}
151156

152-
private void setData(DelphiNode terminator, Set<Block> cases) {
157+
private void setData(DelphiNode terminator, Set<Block> cases, Block fallthrough) {
153158
this.terminator = new Terminator(terminator);
154159
this.cases = cases;
160+
this.fallthrough = fallthrough;
155161
}
156162

157163
@Override
158164
public Set<Block> getCaseSuccessors() {
159165
return Collections.unmodifiableSet(cases);
160166
}
161167

168+
@Override
169+
public Block getFallthroughSuccessor() {
170+
return fallthrough;
171+
}
172+
162173
@Override
163174
public DelphiNode getTerminator() {
164175
return terminator.getTerminatorNode();
@@ -174,11 +185,14 @@ public void replaceInactiveSuccessor(Block inactiveBlock, Block target) {
174185
if (cases.remove(inactiveBlock)) {
175186
cases.add(target);
176187
}
188+
this.fallthrough = getNewTarget(this.fallthrough, inactiveBlock, target);
177189
}
178190

179191
@Override
180192
public String getDescription() {
181-
return String.format("%n\tcases to: %s", getBlocksString(cases));
193+
return String.format(
194+
"%n\tcases to: %s%n\tfallthrough to: %s",
195+
getBlocksString(cases), getBlockString(fallthrough));
182196
}
183197
}
184198

delphi-frontend/src/test/java/au/com/integradev/delphi/cfg/checker/BlockChecker.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public BlockChecker jumpsTo(int successor, int successorWithoutJump) {
164164
return this;
165165
}
166166

167-
public BlockChecker succeedsToCases(int... cases) {
167+
public BlockChecker succeedsToCases(int fallthrough, int... cases) {
168168
Set<Integer> expectedCases = Arrays.stream(cases).boxed().collect(Collectors.toSet());
169169
this.successorChecker =
170170
new BlockDetailChecker(
@@ -183,6 +183,12 @@ public BlockChecker succeedsToCases(int... cases) {
183183
.collect(Collectors.joining(", "))
184184
+ "]")
185185
.containsExactlyInAnyOrderElementsOf(expectedCases);
186+
assertThat(getBlockId(caseSuccessor.getFallthroughSuccessor()))
187+
.withFailMessage(
188+
getBlockDisplay(block)
189+
+ " is expected to have fallthrough successor of B"
190+
+ fallthrough)
191+
.isEqualTo(fallthrough);
186192
});
187193
return this;
188194
}

0 commit comments

Comments
 (0)