Skip to content

Commit af9e715

Browse files
cirrasfourls
authored andcommitted
Handle empty anonymous methods in EmptyRoutine
1 parent b692609 commit af9e715

File tree

6 files changed

+83
-2
lines changed

6 files changed

+83
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- Library path (`DelphiLibraryPath`/`DelphiTranslatedLibraryPath`)
1919
- Browsing path (`DelphiBrowsingPath`)
2020
- Standard library
21+
- Empty anonymous methods are now flagged in `EmptyRoutine`.
22+
- **API:** `AnonymousMethodNode::getStatementBlock` method.
23+
- **API:** `AnonymousMethodNode::isEmpty` method.
2124

2225
## [1.12.2] - 2025-01-06
2326

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020

2121
import au.com.integradev.delphi.utils.InterfaceUtils;
2222
import org.sonar.check.Rule;
23+
import org.sonar.plugins.communitydelphi.api.ast.AnonymousMethodNode;
2324
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
2425
import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode;
2526
import org.sonar.plugins.communitydelphi.api.check.DelphiCheck;
2627
import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext;
28+
import org.sonar.plugins.communitydelphi.api.check.FilePosition;
2729
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineDirective;
2830
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineNameDeclaration;
2931
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
@@ -36,15 +38,30 @@ public class EmptyRoutineCheck extends DelphiCheck {
3638

3739
@Override
3840
public DelphiCheckContext visit(RoutineImplementationNode routine, DelphiCheckContext context) {
39-
if (routine.isEmpty() && shouldAddViolation(routine)) {
41+
if (shouldAddViolation(routine)) {
4042
reportIssue(context, routine.getRoutineNameNode(), MESSAGE);
4143
}
4244
return super.visit(routine, context);
4345
}
4446

47+
@Override
48+
public DelphiCheckContext visit(AnonymousMethodNode anonymousMethod, DelphiCheckContext context) {
49+
if (shouldAddViolation(anonymousMethod)) {
50+
context
51+
.newIssue()
52+
.onFilePosition(FilePosition.from(anonymousMethod.getFirstToken()))
53+
.withMessage(MESSAGE)
54+
.report();
55+
}
56+
return super.visit(anonymousMethod, context);
57+
}
58+
4559
private static boolean shouldAddViolation(RoutineImplementationNode routine) {
46-
DelphiNode block = routine.getBlock();
60+
if (!routine.isEmpty()) {
61+
return false;
62+
}
4763

64+
DelphiNode block = routine.getBlock();
4865
if (block != null && block.getComments().isEmpty()) {
4966
// All exclusions aside, an explanatory comment is mandatory
5067
return true;
@@ -59,4 +76,8 @@ private static boolean shouldAddViolation(RoutineImplementationNode routine) {
5976
&& !declaration.hasDirective(RoutineDirective.VIRTUAL)
6077
&& !InterfaceUtils.implementsMethodOnInterface(declaration);
6178
}
79+
80+
private static boolean shouldAddViolation(AnonymousMethodNode anonymousMethod) {
81+
return anonymousMethod.isEmpty() && anonymousMethod.getStatementBlock().getComments().isEmpty();
82+
}
6283
}

delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/EmptyRoutine.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ <h2>Why is this an issue?</h2>
99
<li>Virtual methods (e.g. to provide a no-op default behaviour for child classes)</li>
1010
<li>Override methods (e.g. to not run behaviour implemented in ancestor classes)</li>
1111
<li>Methods that implement an interface</li>
12+
<li>Anonymous methods</li>
1213
</ul>
1314
<h2>How to fix it</h2>
1415
<p>If the empty routine is an omission, remove it.</p>

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,47 @@ void testOverloadedMethodShouldNotAddIssue() {
200200
.verifyNoIssues();
201201
}
202202

203+
@Test
204+
void testEmptyAnonymousMethodWithoutCommentShouldAddIssue() {
205+
CheckVerifier.newVerifier()
206+
.withCheck(new EmptyRoutineCheck())
207+
.onFile(
208+
new DelphiTestUnitBuilder()
209+
.appendDecl("type")
210+
.appendDecl(" TProc = reference to procedure;")
211+
.appendImpl("procedure Foo;")
212+
.appendImpl("var")
213+
.appendImpl(" Bar: TProc;")
214+
.appendImpl("begin")
215+
.appendImpl(" Bar :=")
216+
.appendImpl(" procedure // Noncompliant")
217+
.appendImpl(" begin")
218+
.appendImpl(" end;")
219+
.appendImpl("end;"))
220+
.verifyIssues();
221+
}
222+
223+
@Test
224+
void testEmptyAnonymousMethodWithCommentShouldNotAddIssue() {
225+
CheckVerifier.newVerifier()
226+
.withCheck(new EmptyRoutineCheck())
227+
.onFile(
228+
new DelphiTestUnitBuilder()
229+
.appendDecl("type")
230+
.appendDecl(" TProc = reference to procedure;")
231+
.appendImpl("procedure Foo;")
232+
.appendImpl("var")
233+
.appendImpl(" Bar: TProc;")
234+
.appendImpl("begin")
235+
.appendImpl(" Bar :=")
236+
.appendImpl(" procedure")
237+
.appendImpl(" begin")
238+
.appendImpl(" // do nothing")
239+
.appendImpl(" end;")
240+
.appendImpl("end;"))
241+
.verifyNoIssues();
242+
}
243+
203244
@Test
204245
void testForwardDeclarationShouldNotAddIssue() {
205246
CheckVerifier.newVerifier()

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/AnonymousMethodNodeImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.antlr.runtime.Token;
2929
import org.sonar.plugins.communitydelphi.api.ast.AnonymousMethodHeadingNode;
3030
import org.sonar.plugins.communitydelphi.api.ast.AnonymousMethodNode;
31+
import org.sonar.plugins.communitydelphi.api.ast.CompoundStatementNode;
3132
import org.sonar.plugins.communitydelphi.api.ast.RoutineParametersNode;
3233
import org.sonar.plugins.communitydelphi.api.ast.RoutineReturnTypeNode;
3334
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineDirective;
@@ -98,6 +99,16 @@ public boolean isProcedure() {
9899
return getRoutineKind() == RoutineKind.PROCEDURE;
99100
}
100101

102+
@Override
103+
public CompoundStatementNode getStatementBlock() {
104+
return (CompoundStatementNode) getChild(1);
105+
}
106+
107+
@Override
108+
public boolean isEmpty() {
109+
return getStatementBlock().isEmpty();
110+
}
111+
101112
@Override
102113
public String getImage() {
103114
if (image == null) {

delphi-frontend/src/main/java/org/sonar/plugins/communitydelphi/api/ast/AnonymousMethodNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,8 @@ public interface AnonymousMethodNode extends ExpressionNode {
4141
boolean isFunction();
4242

4343
boolean isProcedure();
44+
45+
CompoundStatementNode getStatementBlock();
46+
47+
boolean isEmpty();
4448
}

0 commit comments

Comments
 (0)