Skip to content

Commit 3143498

Browse files
EduardoVaz06cirras
authored andcommitted
Create rule FullyQualifiedImportCheck
1 parent ba1fbc7 commit 3143498

File tree

6 files changed

+202
-0
lines changed

6 files changed

+202
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919

2020
### Added
2121

22+
- `FullyQualifiedImportCheck` analysis rule, which flags non-fully qualified imports.
2223
- **API:** `CaseItemStatementNode::getExpressions` method.
2324

2425
### Changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public final class CheckList {
8383
FormatArgumentTypeCheck.class,
8484
FormatStringValidCheck.class,
8585
FreeAndNilTObjectCheck.class,
86+
FullyQualifiedImportCheck.class,
8687
GotoStatementCheck.class,
8788
GroupedFieldDeclarationCheck.class,
8889
GroupedParameterDeclarationCheck.class,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2024 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.checks;
20+
21+
import org.sonar.check.Rule;
22+
import org.sonar.plugins.communitydelphi.api.ast.UnitImportNode;
23+
import org.sonar.plugins.communitydelphi.api.check.DelphiCheck;
24+
import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext;
25+
import org.sonar.plugins.communitydelphi.api.reporting.QuickFix;
26+
import org.sonar.plugins.communitydelphi.api.reporting.QuickFixEdit;
27+
import org.sonar.plugins.communitydelphi.api.symbol.declaration.UnitImportNameDeclaration;
28+
29+
@Rule(key = "FullyQualifiedImport")
30+
public class FullyQualifiedImportCheck extends DelphiCheck {
31+
32+
@Override
33+
public DelphiCheckContext visit(UnitImportNode unitImportNode, DelphiCheckContext context) {
34+
if (!unitImportNode.isResolvedImport()) {
35+
return context;
36+
}
37+
38+
UnitImportNameDeclaration unitImportNameDeclaration = unitImportNode.getImportNameDeclaration();
39+
40+
String unitFullyQualifiedName = unitImportNameDeclaration.getOriginalDeclaration().getImage();
41+
String unitImportName = unitImportNameDeclaration.getImage();
42+
43+
if (unitImportName.length() != unitFullyQualifiedName.length()) {
44+
context
45+
.newIssue()
46+
.onNode(unitImportNode)
47+
.withMessage(
48+
"Fully qualify this unit name (found: \"%s\" expected: \"%s\").",
49+
unitImportName, unitFullyQualifiedName)
50+
.withQuickFixes(
51+
QuickFix.newFix("Fully qualify unit import")
52+
.withEdit(
53+
QuickFixEdit.replace(unitImportNode.getNameNode(), unitFullyQualifiedName)))
54+
.report();
55+
}
56+
57+
return context;
58+
}
59+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<h2>Why is this an issue?</h2>
2+
<p>
3+
Imports should be done using the full name of the unit, as this facilitates code readability, avoids potential ambiguities about which unit is being imported, and ensures consistency throughout the codebase.
4+
</p>
5+
<p>
6+
Using the full name of the units not only improves code clarity and maintenance but also optimizes the compilation process. The compiler does not need to spend time searching implicit scopes to resolve which units are being referenced. By specifying the full unit name, the compiler can immediately locate the necessary files, resulting in faster and more efficient compilation.
7+
</p>
8+
<h2>How to fix it</h2>
9+
<p>
10+
Fully qualify the unit name.
11+
</p>
12+
<pre data-diff-id="1" data-diff-type="noncompliant">
13+
uses
14+
Classes,
15+
SysUtils;
16+
</pre>
17+
<pre data-diff-id="1" data-diff-type="compliant">
18+
uses
19+
System.Classes,
20+
System.SysUtils;
21+
</pre>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"title": "Imports should be fully qualified",
3+
"type": "CODE_SMELL",
4+
"status": "ready",
5+
"remediation": {
6+
"func": "Constant/Issue",
7+
"constantCost": "5min"
8+
},
9+
"code": {
10+
"attribute": "CLEAR",
11+
"impacts": {
12+
"MAINTAINABILITY": "LOW"
13+
}
14+
},
15+
"tags": ["convention"],
16+
"defaultSeverity": "Minor",
17+
"scope": "ALL"
18+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2024 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.checks;
20+
21+
import au.com.integradev.delphi.builders.DelphiTestProgramBuilder;
22+
import au.com.integradev.delphi.builders.DelphiTestUnitBuilder;
23+
import au.com.integradev.delphi.checks.verifier.CheckVerifier;
24+
import org.junit.jupiter.api.Test;
25+
26+
class FullyQualifiedImportCheckTest {
27+
28+
@Test
29+
void testFullyQualifiedImportShouldNotAddIssue() {
30+
var importedUnit = new DelphiTestUnitBuilder().unitName("Scope.UnitU");
31+
32+
var testFile = new DelphiTestUnitBuilder().appendDecl("uses").appendDecl(" Scope.UnitU;");
33+
34+
CheckVerifier.newVerifier()
35+
.withCheck(new FullyQualifiedImportCheck())
36+
.withSearchPathUnit(importedUnit)
37+
.onFile(testFile)
38+
.verifyNoIssues();
39+
}
40+
41+
@Test
42+
void testImportFullyQualifiedWithInKeywordShouldNotAddIssue() {
43+
var importedUnit = new DelphiTestUnitBuilder().unitName("Scope.UnitU");
44+
45+
var testFile =
46+
new DelphiTestProgramBuilder()
47+
.appendDecl("uses")
48+
.appendDecl(" Scope.UnitU in 'Test.UnitU.pas';");
49+
50+
CheckVerifier.newVerifier()
51+
.withCheck(new FullyQualifiedImportCheck())
52+
.withSearchPathUnit(importedUnit)
53+
.onFile(testFile)
54+
.verifyNoIssues();
55+
}
56+
57+
@Test
58+
void testImportNotFullyQualifiedWithInKeywordShouldAddIssue() {
59+
var importedUnit = new DelphiTestUnitBuilder().unitName("Scope.UnitU");
60+
61+
var testFile =
62+
new DelphiTestProgramBuilder()
63+
.appendDecl("uses")
64+
.appendDecl(" // Fix qf1@[+1:2 to +1:7] <<Scope.UnitU>>")
65+
.appendDecl(" UnitU in 'Test.UnitU.pas'; // Noncompliant");
66+
67+
CheckVerifier.newVerifier()
68+
.withCheck(new FullyQualifiedImportCheck())
69+
.withSearchPathUnit(importedUnit)
70+
.onFile(testFile)
71+
.withUnitScopeName("Scope")
72+
.verifyIssues();
73+
}
74+
75+
@Test
76+
void testUnresolvedImportShouldNotAddIssue() {
77+
var testFile = new DelphiTestUnitBuilder().appendDecl("uses").appendDecl(" RandomUnit;");
78+
79+
CheckVerifier.newVerifier()
80+
.withCheck(new FullyQualifiedImportCheck())
81+
.onFile(testFile)
82+
.verifyNoIssues();
83+
}
84+
85+
@Test
86+
void testNotFullyQualifiedImportShouldAddIssue() {
87+
var importedUnit = new DelphiTestUnitBuilder().unitName("Scope.UnitU");
88+
89+
var testFile =
90+
new DelphiTestUnitBuilder()
91+
.appendDecl("uses")
92+
.appendDecl(" // Fix qf1@[+1:2 to +1:7] <<Scope.UnitU>>")
93+
.appendDecl(" UnitU; // Noncompliant");
94+
95+
CheckVerifier.newVerifier()
96+
.withCheck(new FullyQualifiedImportCheck())
97+
.withSearchPathUnit(importedUnit)
98+
.onFile(testFile)
99+
.withUnitScopeName("Scope")
100+
.verifyIssues();
101+
}
102+
}

0 commit comments

Comments
 (0)