Skip to content

Commit 1dd7e5b

Browse files
committed
Improve coverage in RedundantJumpCheck
1 parent fd1ce42 commit 1dd7e5b

File tree

2 files changed

+62
-38
lines changed

2 files changed

+62
-38
lines changed

delphi-checks/src/main/java/au/com/integradev/delphi/checks/RedundantJumpCheck.java

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@
2323
import au.com.integradev.delphi.cfg.api.Block;
2424
import au.com.integradev.delphi.cfg.api.ControlFlowGraph;
2525
import au.com.integradev.delphi.cfg.api.Finally;
26-
import au.com.integradev.delphi.cfg.api.Linear;
2726
import au.com.integradev.delphi.cfg.api.UnconditionalJump;
2827
import org.sonar.check.Rule;
2928
import org.sonar.plugins.communitydelphi.api.ast.AnonymousMethodNode;
3029
import org.sonar.plugins.communitydelphi.api.ast.ArgumentListNode;
31-
import org.sonar.plugins.communitydelphi.api.ast.CompoundStatementNode;
3230
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
3331
import org.sonar.plugins.communitydelphi.api.ast.NameReferenceNode;
3432
import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode;
@@ -53,12 +51,8 @@ public DelphiCheckContext visit(RoutineImplementationNode routine, DelphiCheckCo
5351

5452
@Override
5553
public DelphiCheckContext visit(AnonymousMethodNode routine, DelphiCheckContext context) {
56-
CompoundStatementNode compoundStatementNode =
57-
routine.getFirstChildOfType(CompoundStatementNode.class);
58-
if (compoundStatementNode != null) {
59-
ControlFlowGraph cfg = ControlFlowGraphFactory.create(compoundStatementNode);
60-
cfg.getBlocks().forEach(block -> checkBlock(block, context));
61-
}
54+
ControlFlowGraph cfg = ControlFlowGraphFactory.create(routine.getStatementBlock());
55+
cfg.getBlocks().forEach(block -> checkBlock(block, context));
6256

6357
return super.visit(routine, context);
6458
}
@@ -69,19 +63,20 @@ private void checkBlock(Block block, DelphiCheckContext context) {
6963
}
7064

7165
UnconditionalJump jump = (UnconditionalJump) block;
72-
Block successorWithoutJump = jump.getSuccessorIfRemoved();
7366
DelphiNode terminator = jump.getTerminator();
7467

7568
RoutineNameDeclaration routineNameDeclaration = getRoutineNameDeclaration(terminator);
69+
if (routineNameDeclaration == null) {
70+
return;
71+
}
72+
7673
if (!isContinueOrExit(routineNameDeclaration)
7774
|| isExitWithExpression(routineNameDeclaration, terminator)) {
7875
return;
7976
}
8077

8178
Block successor = jump.getSuccessor();
82-
successorWithoutJump = nonEmptySuccessor(successorWithoutJump);
83-
84-
if (!successorWithoutJump.equals(successor)) {
79+
if (!successor.equals(jump.getSuccessorIfRemoved())) {
8580
return;
8681
}
8782

@@ -116,46 +111,31 @@ private static boolean onlyFinallyBlocksBeforeEnd(Block finallyBlock) {
116111
}
117112

118113
private static RoutineNameDeclaration getRoutineNameDeclaration(DelphiNode node) {
119-
if (!(node instanceof NameReferenceNode)) {
120-
return null;
114+
NameDeclaration nameDeclaration = null;
115+
if (node instanceof NameReferenceNode) {
116+
nameDeclaration = ((NameReferenceNode) node).getNameDeclaration();
121117
}
122-
NameDeclaration nameDeclaration = ((NameReferenceNode) node).getNameDeclaration();
123-
if (!(nameDeclaration instanceof RoutineNameDeclaration)) {
124-
return null;
118+
if (nameDeclaration instanceof RoutineNameDeclaration) {
119+
return (RoutineNameDeclaration) nameDeclaration;
125120
}
126-
return (RoutineNameDeclaration) nameDeclaration;
121+
return null;
127122
}
128123

129124
private static boolean isContinueOrExit(RoutineNameDeclaration routineNameDeclaration) {
130-
if (routineNameDeclaration == null) {
131-
return false;
132-
}
133125
String fullyQualifiedName = routineNameDeclaration.fullyQualifiedName();
134126
return fullyQualifiedName.equals("System.Continue") || fullyQualifiedName.equals("System.Exit");
135127
}
136128

137129
private static boolean isExitWithExpression(
138130
RoutineNameDeclaration routineNameDeclaration, DelphiNode statement) {
139-
if (routineNameDeclaration == null) {
140-
return false;
141-
}
142131
String fullyQualifiedName = routineNameDeclaration.fullyQualifiedName();
143132
if (!fullyQualifiedName.equals("System.Exit")) {
144133
return false;
145134
}
146-
ArgumentListNode argumentList =
147-
statement.getParent().getFirstChildOfType(ArgumentListNode.class);
148-
if (argumentList == null) {
149-
return false;
150-
}
151-
return argumentList.getArgumentNodes().size() == 1;
152-
}
153135

154-
private static Block nonEmptySuccessor(Block initialBlock) {
155-
Block result = initialBlock;
156-
while (result.getElements().isEmpty() && result instanceof Linear) {
157-
result = ((Linear) result).getSuccessor();
158-
}
159-
return result;
136+
var argumentList = statement.getParent().getFirstChildOfType(ArgumentListNode.class);
137+
int arguments = argumentList == null ? 0 : argumentList.getArgumentNodes().size();
138+
139+
return arguments > 0;
160140
}
161141
}

delphi-checks/src/test/java/au/com/integradev/delphi/checks/RedundantJumpCheckTest.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,21 @@ void testExitWithValueBeforeEndShouldNotAddIssue() {
181181
doExitTest(List.of("Exit(42);", "Foo;"), false);
182182
}
183183

184+
@Test
185+
void testExitWithEmptyArgumentListShouldAddIssue() {
186+
doExitTest(List.of("Exit(); // Noncompliant"), true);
187+
}
188+
189+
@Test
190+
void testExitWithEmptyArgumentListAtEndShouldAddIssue() {
191+
doExitTest(List.of("Foo;", "Exit(); // Noncompliant"), true);
192+
}
193+
194+
@Test
195+
void testExitWithEmptyArgumentListBeforeEndShouldNotAddIssue() {
196+
doExitTest(List.of("Exit();", "Foo;"), false);
197+
}
198+
184199
@Test
185200
void testExitShouldAddIssue() {
186201
doExitTest(List.of("Exit; // Noncompliant"), true);
@@ -193,7 +208,7 @@ void testExitAtEndShouldAddIssue() {
193208

194209
@Test
195210
void testExitBeforeEndShouldNotAddIssue() {
196-
doExitTest(List.of("Exit; // Noncompliant", "Foo;"), false);
211+
doExitTest(List.of("Exit;", "Foo;"), false);
197212
}
198213

199214
@Test
@@ -353,4 +368,33 @@ void testAnonymousMethodExitShouldAddIssue() {
353368
doExitTest(
354369
List.of("var A := procedure", " begin", " Exit; // Noncompliant", " end;"), true);
355370
}
371+
372+
@Test
373+
void testGotoShouldNotAddIssue() {
374+
CheckVerifier.newVerifier()
375+
.withCheck(new RedundantJumpCheck())
376+
.onFile(
377+
new DelphiTestUnitBuilder()
378+
.appendImpl("procedure Test;")
379+
.appendImpl("label NextLine;")
380+
.appendImpl("begin")
381+
.appendImpl(" goto NextLine;")
382+
.appendImpl(" NextLine:")
383+
.appendImpl("end;"))
384+
.verifyNoIssues();
385+
}
386+
387+
@Test
388+
void testAsmRoutineShouldNotAddIssue() {
389+
CheckVerifier.newVerifier()
390+
.withCheck(new RedundantJumpCheck())
391+
.onFile(
392+
new DelphiTestUnitBuilder()
393+
.appendImpl("procedure AsmRoutine;")
394+
.appendImpl("asm")
395+
.appendImpl(" JMP @NextLine")
396+
.appendImpl(" @NextLine:")
397+
.appendImpl("end;"))
398+
.verifyNoIssues();
399+
}
356400
}

0 commit comments

Comments
 (0)