Skip to content

Commit 45e51a1

Browse files
committed
fixup! Add ControlFlowGraph and implementation
1 parent 6d2f218 commit 45e51a1

File tree

8 files changed

+42
-42
lines changed

8 files changed

+42
-42
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ public ControlFlowGraph build() {
7171
block.updateBlockData(map);
7272
}
7373

74-
ControlFlowGraph cfg =
74+
ControlFlowGraphImpl cfg =
7575
new ControlFlowGraphImpl(
76-
map.get(currentBlock), map.get(exitBlocks.peek()), new ArrayList<>(map.values()))
77-
.pruned();
76+
map.get(currentBlock), map.get(exitBlocks.peek()), new ArrayList<>(map.values()));
77+
cfg.prune();
7878

7979
populatePredecessors(cfg);
8080
populateIds(cfg);
@@ -203,7 +203,7 @@ public ProtoBlock getCatchTarget(Type exceptionType) {
203203
.orElse(getExitBlock());
204204
}
205205

206-
private boolean isCompatibleType(Type exceptionType, Type catchType) {
206+
private static boolean isCompatibleType(Type exceptionType, Type catchType) {
207207
return exceptionType.is(catchType) || exceptionType.isDescendantOf(catchType);
208208
}
209209

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public List<Block> getBlocks() {
5757
}
5858

5959
/// Removes redundant blocks from the graph and updates their neighbouring blocks.
60-
public ControlFlowGraphImpl pruned() {
60+
public void prune() {
6161
Set<Block> inactiveBlocks = new HashSet<>();
6262

6363
do {

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@
7676
import org.sonarsource.analyzer.commons.collections.ListUtils;
7777

7878
/**
79-
* This visitor populates the {@code ControlFlowGraphBuilder} to construct a control flow
80-
* graph. Generally, the statements and elements are traversed backward simplify the construction of
81-
* a directed graph. `Block` objects are typically are ordered in way they are evaluated.
79+
* This visitor populates the {@link ControlFlowGraphBuilder} to construct a control flow graph.
80+
* Generally, the statements and elements are traversed backward simplify the construction of a
81+
* directed graph. `Block` objects are typically are ordered in way they are evaluated.
8282
*/
8383
class ControlFlowGraphVisitor implements DelphiParserVisitor<ControlFlowGraphBuilder> {
8484

@@ -139,8 +139,8 @@ public ControlFlowGraphBuilder visit(ArgumentNode node, ControlFlowGraphBuilder
139139
}
140140

141141
/**
142-
* {@code NameReferenceNode} has overloaded meanings in Delphi. The control flow intrinsics
143-
* are handled individually.
142+
* {@code NameReferenceNode} has overloaded meanings in Delphi. The control flow intrinsics are
143+
* handled individually.
144144
*/
145145
@Override
146146
public ControlFlowGraphBuilder visit(NameReferenceNode node, ControlFlowGraphBuilder builder) {
@@ -158,7 +158,7 @@ public ControlFlowGraphBuilder visit(NameReferenceNode node, ControlFlowGraphBui
158158
case "System.Break":
159159
return buildControlFlowStatement(node, builder.getBreakTarget(), builder);
160160
case "System.Halt":
161-
builder.addBlock(newBlock().withTerminator(node));
161+
builder.addBlock(newBlock().withProgramTerminator(node));
162162
return builder;
163163
case "System.Continue":
164164
return buildControlFlowStatement(node, builder.getContinueTarget(), builder);
@@ -171,7 +171,7 @@ public ControlFlowGraphBuilder visit(NameReferenceNode node, ControlFlowGraphBui
171171
return builder;
172172
}
173173

174-
private ControlFlowGraphBuilder buildControlFlowStatement(
174+
private static ControlFlowGraphBuilder buildControlFlowStatement(
175175
DelphiNode node, ProtoBlock target, ControlFlowGraphBuilder builder) {
176176
if (target == null) {
177177
throw new IllegalStateException(
@@ -181,7 +181,7 @@ private ControlFlowGraphBuilder buildControlFlowStatement(
181181
return builder;
182182
}
183183

184-
private void handleExceptionalPaths(ControlFlowGraphBuilder builder) {
184+
private static void handleExceptionalPaths(ControlFlowGraphBuilder builder) {
185185
if (!builder.inTryContext()) {
186186
// Only consider routines as potentially exceptional if in a `try` context.
187187
return;
@@ -568,11 +568,9 @@ private ControlFlowGraphBuilder buildTryFinally(
568568
builder.pushLoopContext(builder.getCurrentBlock(), builder.getCurrentBlock());
569569
builder.pushExitBlock(builder.getCurrentBlock());
570570

571-
ProtoBlock beforeFinally = builder.addBlockBeforeCurrent();
571+
builder.addBlockBeforeCurrent();
572572

573573
// Body
574-
builder.setCurrentBlock(beforeFinally);
575-
576574
builder.pushTryFinallyContext();
577575
build(node.getStatementList(), builder);
578576
builder.popTryContext();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import java.util.HashSet;
2323
import java.util.Set;
2424

25-
/** A {@code finally} block whose control flow depends on the existence previous exceptions */
25+
/** A {@code finally} block whose control flow depends on the existence of previous exceptions */
2626
public interface Finally extends Block {
2727
/**
2828
* Next block in the {@link ControlFlowGraph} without exceptional circumstances

delphi-frontend/src/main/java/au/com/integradev/delphi/cfg/api/Sink.java renamed to delphi-frontend/src/main/java/au/com/integradev/delphi/cfg/api/Halt.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
import java.util.Collections;
2222
import java.util.Set;
2323

24-
/** A block which has no successors by design, e.g., {@code Exit} in a routine */
25-
public interface Sink extends Block, Terminated {
24+
/** A block which represents a {@code Halt}, an abrupt process termination */
25+
public interface Halt extends Block, Terminated {
2626
@Override
2727
default Set<Block> getSuccessors() {
2828
return Collections.emptySet();

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
import au.com.integradev.delphi.cfg.api.Branch;
2323
import au.com.integradev.delphi.cfg.api.Cases;
2424
import au.com.integradev.delphi.cfg.api.Finally;
25+
import au.com.integradev.delphi.cfg.api.Halt;
2526
import au.com.integradev.delphi.cfg.api.Linear;
26-
import au.com.integradev.delphi.cfg.api.Sink;
2727
import au.com.integradev.delphi.cfg.api.Terminus;
2828
import au.com.integradev.delphi.cfg.api.UnconditionalJump;
2929
import au.com.integradev.delphi.cfg.api.UnknownException;
@@ -50,9 +50,9 @@ public static ProtoBlockBuilder newBlock() {
5050
return new ProtoBlockBuilder();
5151
}
5252

53-
public ProtoBlockBuilder withTerminator(DelphiNode terminator) {
54-
this.blockSupplier = SinkImpl::new;
55-
this.dataSetter = (blocks, block) -> ((SinkImpl) block).setData(terminator);
53+
public ProtoBlockBuilder withProgramTerminator(DelphiNode terminator) {
54+
this.blockSupplier = HaltImpl::new;
55+
this.dataSetter = (blocks, block) -> ((HaltImpl) block).setData(terminator);
5656
return this;
5757
}
5858

@@ -314,10 +314,10 @@ public String getDescription() {
314314
}
315315
}
316316

317-
static class SinkImpl extends BlockImpl implements Sink {
317+
static class HaltImpl extends BlockImpl implements Halt {
318318
private Terminator terminator;
319319

320-
protected SinkImpl(List<DelphiNode> elements) {
320+
protected HaltImpl(List<DelphiNode> elements) {
321321
super(elements);
322322
}
323323

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,17 @@
8080
class ControlFlowGraphTest {
8181
private static final Logger LOG = LoggerFactory.getLogger(ControlFlowGraphTest.class);
8282

83-
private ControlFlowGraph buildCFG(String input) {
84-
return buildCFG(Collections.emptyMap(), input);
83+
private ControlFlowGraph buildCfg(String input) {
84+
return buildCfg(Collections.emptyMap(), input);
8585
}
8686

87-
private ControlFlowGraph buildCFG(List<String> variables, String input) {
88-
return buildCFG(Map.of("var", variables), input);
87+
private ControlFlowGraph buildCfg(List<String> variables, String input) {
88+
return buildCfg(Map.of("var", variables), input);
8989
}
9090

91-
private ControlFlowGraph buildCFG(Map<String, List<String>> sections, String input) {
91+
private ControlFlowGraph buildCfg(Map<String, List<String>> sections, String input) {
9292
try {
93-
var tempFile = File.createTempFile("CFGTest-", ".pas");
93+
var tempFile = File.createTempFile("CfgTest-", ".pas");
9494
tempFile.deleteOnExit();
9595

9696
StringBuilder content = new StringBuilder();
@@ -155,11 +155,11 @@ private void test(String input, GraphChecker checker) {
155155
}
156156

157157
private void test(List<String> variables, String input, GraphChecker checker) {
158-
checker.check(buildCFG(variables, input));
158+
checker.check(buildCfg(variables, input));
159159
}
160160

161161
private void test(Map<String, List<String>> sections, String input, GraphChecker checker) {
162-
checker.check(buildCFG(sections, input));
162+
checker.check(buildCfg(sections, input));
163163
}
164164

165165
private static Path createStandardLibrary() {
@@ -225,15 +225,15 @@ private Consumer<DelphiNode> unaryOpTest(UnaryOperator operator) {
225225
}
226226

227227
@Test
228-
void testEmptyCFG() {
229-
final ControlFlowGraph cfg = buildCFG("");
228+
void testEmptyCfg() {
229+
final ControlFlowGraph cfg = buildCfg("");
230230
checker().check(cfg);
231231
assertThat(cfg.getEntryBlock().getSuccessors()).as("entry is an exit").isEmpty();
232232
}
233233

234234
@Test
235-
void testSimplestCFG() {
236-
final ControlFlowGraph cfg = buildCFG("Foo;");
235+
void testSimplestCfg() {
236+
final ControlFlowGraph cfg = buildCfg("Foo;");
237237
checker(block(element(NameReferenceNode.class, "Foo")).succeedsTo(0)).check(cfg);
238238
Block entry = cfg.getEntryBlock();
239239
assertThat(entry)
@@ -243,7 +243,7 @@ void testSimplestCFG() {
243243
assertThat(exit)
244244
.withFailMessage("Expecting entry block's successor to be the exit block")
245245
.isEqualTo(cfg.getExitBlock())
246-
.withFailMessage("Expecting entry block's successor to be the of type Terminus.")
246+
.withFailMessage("Expecting entry block's successor to be of type Terminus.")
247247
.isInstanceOf(Terminus.class);
248248
}
249249

@@ -671,14 +671,16 @@ void testForInConditionalContinue() {
671671

672672
@Test
673673
void testBreakOutsideOfLoop() {
674-
assertThatThrownBy(() -> test("Break;", checker()))
674+
GraphChecker checker = checker();
675+
assertThatThrownBy(() -> test("Break;", checker))
675676
.withFailMessage("'Break' statement not in loop statement.")
676677
.isInstanceOf(IllegalStateException.class);
677678
}
678679

679680
@Test
680681
void testContinueOutsideOfLoop() {
681-
assertThatThrownBy(() -> test("Continue;", checker()))
682+
GraphChecker checker = checker();
683+
assertThatThrownBy(() -> test("Continue;", checker))
682684
.withFailMessage("'Continue' statement not in loop statement.")
683685
.isInstanceOf(IllegalStateException.class);
684686
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import au.com.integradev.delphi.cfg.api.Cases;
2626
import au.com.integradev.delphi.cfg.api.Finally;
2727
import au.com.integradev.delphi.cfg.api.Linear;
28-
import au.com.integradev.delphi.cfg.api.Sink;
28+
import au.com.integradev.delphi.cfg.api.Halt;
2929
import au.com.integradev.delphi.cfg.api.Terminated;
3030
import au.com.integradev.delphi.cfg.api.UnconditionalJump;
3131
import au.com.integradev.delphi.cfg.api.UnknownException;
@@ -212,7 +212,7 @@ public BlockChecker succeedsToWithExceptions(int successor, int... unknownExcept
212212
}
213213

214214
public BlockChecker isSink() {
215-
successorChecker = new BlockDetailChecker(block -> assertBlockIsType(block, Sink.class));
215+
successorChecker = new BlockDetailChecker(block -> assertBlockIsType(block, Halt.class));
216216
return this;
217217
}
218218

0 commit comments

Comments
 (0)