Skip to content

Commit 1058683

Browse files
committed
fixup! Add ControlFlowGraph and implementation
1 parent 876766c commit 1058683

File tree

3 files changed

+120
-5
lines changed

3 files changed

+120
-5
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.sonar.plugins.communitydelphi.api.ast.SimpleNameDeclarationNode;
6464
import org.sonar.plugins.communitydelphi.api.ast.StatementListNode;
6565
import org.sonar.plugins.communitydelphi.api.ast.StatementNode;
66+
import org.sonar.plugins.communitydelphi.api.ast.TextLiteralNode;
6667
import org.sonar.plugins.communitydelphi.api.ast.TryStatementNode;
6768
import org.sonar.plugins.communitydelphi.api.ast.UnaryExpressionNode;
6869
import org.sonar.plugins.communitydelphi.api.ast.VarStatementNode;
@@ -102,6 +103,12 @@ public ControlFlowGraphBuilder visit(NilLiteralNode node, ControlFlowGraphBuilde
102103
return builder;
103104
}
104105

106+
@Override
107+
public ControlFlowGraphBuilder visit(TextLiteralNode node, ControlFlowGraphBuilder builder) {
108+
builder.addElement(node);
109+
return builder;
110+
}
111+
105112
@Override
106113
public ControlFlowGraphBuilder visit(
107114
SimpleNameDeclarationNode node, ControlFlowGraphBuilder builder) {

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

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
import org.sonar.plugins.communitydelphi.api.ast.RealLiteralNode;
7272
import org.sonar.plugins.communitydelphi.api.ast.RepeatStatementNode;
7373
import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode;
74+
import org.sonar.plugins.communitydelphi.api.ast.SimpleNameDeclarationNode;
75+
import org.sonar.plugins.communitydelphi.api.ast.TextLiteralNode;
7476
import org.sonar.plugins.communitydelphi.api.ast.TryStatementNode;
7577
import org.sonar.plugins.communitydelphi.api.ast.UnaryExpressionNode;
7678
import org.sonar.plugins.communitydelphi.api.ast.WhileStatementNode;
@@ -905,7 +907,9 @@ void testTryExceptRaise1stCatch() {
905907
+ "end;",
906908
checker(
907909
block(element(TryStatementNode.class)).succeedsTo(4),
908-
block(element(NameReferenceNode.class, "EAbort.Create"))
910+
block(
911+
element(TextLiteralNode.class, "''"),
912+
element(NameReferenceNode.class, "EAbort.Create"))
909913
.succeedsToWithExceptions(3, 0, 1, 2),
910914
terminator(RaiseStatementNode.class, TerminatorKind.RAISE).jumpsTo(2, 0),
911915
block(element(NameDeclarationNode.class, "E"), element(NameReferenceNode.class, "Bar"))
@@ -931,7 +935,9 @@ void testTryExceptRaise2ndCatch() {
931935
+ "end;",
932936
checker(
933937
block(element(TryStatementNode.class)).succeedsTo(4),
934-
block(element(NameReferenceNode.class, "Exception.Create"))
938+
block(
939+
element(TextLiteralNode.class, "''"),
940+
element(NameReferenceNode.class, "Exception.Create"))
935941
.succeedsToWithExceptions(3, 0, 1, 2),
936942
terminator(RaiseStatementNode.class, TerminatorKind.RAISE).jumpsTo(1, 0),
937943
block(element(NameDeclarationNode.class, "E"), element(NameReferenceNode.class, "Bar"))
@@ -947,7 +953,9 @@ void testTryBareExceptRaise() {
947953
"try raise Exception.Create(''); except Bar; end;",
948954
checker(
949955
block(element(TryStatementNode.class)).succeedsTo(3),
950-
block(element(NameReferenceNode.class, "Exception.Create"))
956+
block(
957+
element(TextLiteralNode.class, "''"),
958+
element(NameReferenceNode.class, "Exception.Create"))
951959
.succeedsToWithExceptions(2, 1),
952960
terminator(RaiseStatementNode.class, TerminatorKind.RAISE).jumpsTo(1, 0),
953961
block(element(NameReferenceNode.class, "Bar")).succeedsTo(0)));
@@ -1035,7 +1043,9 @@ void testTryBareExcept() {
10351043
"try raise Exception.Create('') except Foo end;",
10361044
checker(
10371045
block(element(TryStatementNode.class)).succeedsTo(3),
1038-
block(element(NameReferenceNode.class, "Exception.Create"))
1046+
block(
1047+
element(TextLiteralNode.class, "''"),
1048+
element(NameReferenceNode.class, "Exception.Create"))
10391049
.succeedsToWithExceptions(2, 1),
10401050
terminator(RaiseStatementNode.class, TerminatorKind.RAISE).jumpsTo(1, 0),
10411051
block(element(NameReferenceNode.class, "Foo")).succeedsTo(0)));
@@ -1323,4 +1333,99 @@ void testInlineAssemblyIsIgnored() {
13231333
"Foo; asm XOR EAX, EAX end;",
13241334
checker(block(element(NameReferenceNode.class, "Foo")).succeedsTo(0)));
13251335
}
1336+
1337+
@Test
1338+
void testComplexConstructions() {
1339+
test(
1340+
Map.of("label", List.of("Label1")),
1341+
"Foo1;\n"
1342+
+ "with TObject.Create do begin\n"
1343+
+ " WithBar1;\n"
1344+
+ " WithBar2;\n"
1345+
+ "end;\n"
1346+
+ "Foo2;\n"
1347+
+ "for var A := 1 + +1 to 2 + 2 do begin\n"
1348+
+ " ForBar1;\n"
1349+
+ " ForBar2;\n"
1350+
+ " if A = 4 then goto Label1;\n"
1351+
+ "end;\n"
1352+
+ "Foo3;\n"
1353+
+ "while A and B or C do begin\n"
1354+
+ " WhileBar1;\n"
1355+
+ " Label1:\n"
1356+
+ " WhileBar2;\n"
1357+
+ " try\n"
1358+
+ " Break;\n"
1359+
+ " finally\n"
1360+
+ " var X := '123';\n"
1361+
+ " if D or E then X := 'a'\n"
1362+
+ " else X := 'b';\n"
1363+
+ " end;\n"
1364+
+ "end;\n"
1365+
+ "Foo4;",
1366+
checker(
1367+
block(element(NameReferenceNode.class, "Foo1")).succeedsTo(21),
1368+
block(element(NameReferenceNode.class, "TObject.Create")).succeedsTo(20),
1369+
block(
1370+
element(NameReferenceNode.class, "WithBar1"),
1371+
element(NameReferenceNode.class, "WithBar2"))
1372+
.succeedsTo(19),
1373+
block(element(NameReferenceNode.class, "Foo2")).succeedsTo(18),
1374+
block(
1375+
element(IntegerLiteralNode.class, "1"),
1376+
element(IntegerLiteralNode.class, "1"),
1377+
element(UnaryExpressionNode.class).withCheck(unaryOpTest(UnaryOperator.PLUS)),
1378+
element(BinaryExpressionNode.class).withCheck(binaryOpTest(BinaryOperator.ADD)))
1379+
.succeedsTo(17),
1380+
block(
1381+
element(IntegerLiteralNode.class, "2"),
1382+
element(IntegerLiteralNode.class, "2"),
1383+
element(BinaryExpressionNode.class).withCheck(binaryOpTest(BinaryOperator.ADD)))
1384+
.succeedsTo(14),
1385+
block(
1386+
element(NameReferenceNode.class, "ForBar1"),
1387+
element(NameReferenceNode.class, "ForBar2"),
1388+
element(NameReferenceNode.class, "A"),
1389+
element(IntegerLiteralNode.class, "4"),
1390+
element(BinaryExpressionNode.class)
1391+
.withCheck(binaryOpTest(BinaryOperator.EQUAL)))
1392+
.branchesTo(15, 14)
1393+
.withTerminator(IfStatementNode.class),
1394+
block().jumpsTo(8, 14).withTerminator(GotoStatementNode.class, TerminatorKind.GOTO),
1395+
block(element(SimpleNameDeclarationNode.class, "A"))
1396+
.branchesTo(16, 13)
1397+
.withTerminator(ForToStatementNode.class),
1398+
block(element(NameReferenceNode.class, "Foo3")).succeedsTo(12),
1399+
block(element(NameReferenceNode.class, "A"))
1400+
.branchesTo(11, 10)
1401+
.withTerminator(BinaryExpressionNode.class)
1402+
.withTerminatorNodeCheck(binaryOpTest(BinaryOperator.AND)),
1403+
block(element(NameReferenceNode.class, "B"))
1404+
.branchesTo(9, 10)
1405+
.withTerminator(BinaryExpressionNode.class)
1406+
.withTerminatorNodeCheck(binaryOpTest(BinaryOperator.OR)),
1407+
block(element(NameReferenceNode.class, "C"))
1408+
.branchesTo(9, 1)
1409+
.withTerminator(WhileStatementNode.class),
1410+
block(element(NameReferenceNode.class, "WhileBar1")).succeedsTo(8),
1411+
block(element(NameReferenceNode.class, "WhileBar2"), element(TryStatementNode.class))
1412+
.succeedsTo(7),
1413+
block().jumpsTo(6, 6).withTerminator(NameReferenceNode.class, TerminatorKind.BREAK),
1414+
block(
1415+
element(TextLiteralNode.class, "'123'"),
1416+
element(SimpleNameDeclarationNode.class, "X"),
1417+
element(NameReferenceNode.class, "D"))
1418+
.branchesTo(4, 5)
1419+
.withTerminator(BinaryExpressionNode.class)
1420+
.withTerminatorNodeCheck(binaryOpTest(BinaryOperator.OR)),
1421+
block(element(NameReferenceNode.class, "E"))
1422+
.branchesTo(4, 3)
1423+
.withTerminator(IfStatementNode.class),
1424+
block(element(TextLiteralNode.class, "'a'"), element(NameReferenceNode.class, "X"))
1425+
.succeedsTo(2),
1426+
block(element(TextLiteralNode.class, "'b'"), element(NameReferenceNode.class, "X"))
1427+
.succeedsTo(2),
1428+
block().succeedsToWithExit(12, 0),
1429+
block(element(NameReferenceNode.class, "Foo4")).succeedsTo(0)));
1430+
}
13261431
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ private BlockChecker(ElementChecker... elementCheckers) {
7272
public void check(final Block block) {
7373
assertThat(block.getElements()).as("elements count").hasSize(elementCheckers.size());
7474
for (int elementId = 0; elementId < elementCheckers.size(); elementId++) {
75-
elementCheckers.get(elementId).check(block.getElements().get(elementId));
75+
elementCheckers
76+
.get(elementId)
77+
.withBlockId(((BlockImpl) block).getId(), elementId)
78+
.check(block.getElements().get(elementId));
7679
}
7780
assertThat(successorChecker)
7881
.withFailMessage("%s should have its successors declared", getBlockDisplay(block))

0 commit comments

Comments
 (0)