Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit 3b48b76

Browse files
authored
feat: add method call chains support on ban-name ident (#1034)
* Added breadcrumb on ban-name's visitor - Added tests - Changed docs * Fixed visitor breadcrumb build logic * Added more tests * Updated docs * Updated issue matches
1 parent dea2cc0 commit 3b48b76

File tree

6 files changed

+121
-10
lines changed

6 files changed

+121
-10
lines changed

lib/src/analyzers/lint_analyzer/rules/rules_list/ban_name/ban_name_rule.dart

+23-2
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,32 @@ class BanNameRule extends CommonRule {
4242

4343
source.unit.visitChildren(visitor);
4444

45-
return visitor.nodes
45+
final filteredNodeList = visitor.nodes.where((node) {
46+
if (node.endNode != null) {
47+
final inlineNode = source.content
48+
.substring(
49+
node.node.offset,
50+
node.endNode!.end,
51+
)
52+
.replaceAll('\n', '');
53+
54+
if (!inlineNode.contains(node.fullName)) {
55+
return false;
56+
}
57+
}
58+
59+
return true;
60+
});
61+
62+
return filteredNodeList
4663
.map(
4764
(node) => createIssue(
4865
rule: this,
49-
location: nodeLocation(node: node.node, source: source),
66+
location: nodeLocation(
67+
node: node.node,
68+
source: source,
69+
endNode: node.endNode,
70+
),
5071
message: node.message,
5172
),
5273
)

lib/src/analyzers/lint_analyzer/rules/rules_list/ban_name/visitor.dart

+41-6
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ part of 'ban_name_rule.dart';
33
class _Visitor extends GeneralizingAstVisitor<void> {
44
final Map<String, _BanNameConfigEntry> _entryMap;
55

6-
final _nodes = <_NodeWithMessage>[];
6+
final _nodes = <_NodeInfo>[];
77

8-
Iterable<_NodeWithMessage> get nodes => _nodes;
8+
Iterable<_NodeInfo> get nodes => _nodes;
9+
10+
final _nodeBreadcrumb = <String, AstNode>{};
911

1012
_Visitor(List<_BanNameConfigEntry> entries)
1113
: _entryMap = Map.fromEntries(entries.map((e) => MapEntry(e.ident, e)));
@@ -39,18 +41,51 @@ class _Visitor extends GeneralizingAstVisitor<void> {
3941
}
4042

4143
void _visitIdent(AstNode node, String name) {
44+
final prevNode =
45+
_nodeBreadcrumb.isNotEmpty ? _nodeBreadcrumb.values.last : null;
46+
if (node.offset - 1 == prevNode?.end) {
47+
_nodeBreadcrumb.addAll({name: node});
48+
} else {
49+
_nodeBreadcrumb.clear();
50+
}
51+
52+
if (_nodeBreadcrumb.isEmpty) {
53+
_nodeBreadcrumb.addAll({name: node});
54+
}
55+
4256
if (_entryMap.containsKey(name)) {
43-
_nodes.add(_NodeWithMessage(
57+
_nodes.add(_NodeInfo(
4458
node,
45-
'${_entryMap[name]!.description} ($name is banned)',
59+
fullName: name,
60+
message: '${_entryMap[name]!.description} ($name is banned)',
61+
));
62+
63+
return;
64+
}
65+
66+
final breadcrumbString = _nodeBreadcrumb.keys.join('.');
67+
if (_entryMap.containsKey(breadcrumbString)) {
68+
_nodes.add(_NodeInfo(
69+
_nodeBreadcrumb.values.first,
70+
fullName: breadcrumbString,
71+
message:
72+
'${_entryMap[breadcrumbString]!.description} ($breadcrumbString is banned)',
73+
endNode: _nodeBreadcrumb.values.last,
4674
));
4775
}
4876
}
4977
}
5078

51-
class _NodeWithMessage {
79+
class _NodeInfo {
5280
final AstNode node;
81+
final String fullName;
5382
final String message;
83+
final AstNode? endNode;
5484

55-
_NodeWithMessage(this.node, this.message);
85+
_NodeInfo(
86+
this.node, {
87+
required this.fullName,
88+
required this.message,
89+
this.endNode,
90+
});
5691
}

test/src/analyzers/lint_analyzer/rules/rules_list/ban_name/ban_name_rule_test.dart

+18-2
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,21 @@ void main() {
2727
{'ident': 'showDialog', 'description': 'Please use myShowDialog'},
2828
{'ident': 'strangeName', 'description': 'The name is too strange'},
2929
{'ident': 'AnotherStrangeName', 'description': 'Oops'},
30+
{
31+
'ident': 'StrangeClass.someMethod',
32+
'description': 'Please use NonStrangeClass.someMethod instead',
33+
},
34+
{
35+
'ident': 'DateTime.now',
36+
'description': 'Please use clock.now instead',
37+
},
3038
],
3139
}).check(unit);
3240

3341
RuleTestHelper.verifyIssues(
3442
issues: issues,
35-
startLines: [6, 7, 9, 12, 15, 16],
36-
startColumns: [3, 12, 7, 1, 1, 12],
43+
startLines: [7, 8, 10, 13, 16, 17, 20, 23, 24, 26],
44+
startColumns: [3, 12, 7, 1, 1, 12, 1, 1, 1, 28],
3745
locationTexts: [
3846
'showDialog',
3947
'showDialog',
@@ -43,6 +51,10 @@ void main() {
4351
' late var strangeName; // LINT\n'
4452
'}',
4553
'strangeName',
54+
'StrangeClass.someMethod();',
55+
'DateTime.now();',
56+
'DateTime.now()',
57+
'DateTime.now',
4658
],
4759
messages: [
4860
'Please use myShowDialog (showDialog is banned)',
@@ -51,6 +63,10 @@ void main() {
5163
'The name is too strange (strangeName is banned)',
5264
'Oops (AnotherStrangeName is banned)',
5365
'The name is too strange (strangeName is banned)',
66+
'Please use NonStrangeClass.someMethod instead (StrangeClass.someMethod is banned)',
67+
'Please use clock.now instead (DateTime.now is banned)',
68+
'Please use clock.now instead (DateTime.now is banned)',
69+
'Please use clock.now instead (DateTime.now is banned)',
5470
],
5571
);
5672
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class StrangeClass {
2+
void someMethod();
3+
}
4+
5+
class NonStrangeClass {
6+
void someMethod();
7+
}

test/src/analyzers/lint_analyzer/rules/rules_list/ban_name/examples/example.dart

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dialog.dart';
22
import 'dialog.dart' as material;
3+
import 'classes.dart';
34

45
void func() {
56
myShowDialog('some_arguments', 'another_argument');
@@ -15,3 +16,13 @@ void strangeName() {} // LINT
1516
class AnotherStrangeName {
1617
late var strangeName; // LINT
1718
}
19+
20+
StrangeClass.someMethod(); // LINT
21+
NonStrangeClass.someMethod();
22+
23+
DateTime.now(); // LINT
24+
DateTime.now().day; // LINT
25+
class DateTimeTest {
26+
final currentTimestamp = DateTime.now(); // LINT
27+
}
28+
DateTime now = DateTime(2022);

website/docs/rules/common/ban-name.mdx

+21
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Example: When you add some extra functionalities to built-in Flutter functions (
99
:::caution
1010

1111
When trying to ban some methods in your package, it also triggers on imported from an external package code.
12+
But you can specify the name to ban (ex: 'DateTime.now' instead of 'now').
1213

1314
:::
1415

@@ -30,12 +31,28 @@ void strangeName() {} // LINT
3031
class AnotherStrangeName {
3132
late var strangeName; // LINT
3233
}
34+
35+
StrangeClass.someMethod(); // LINT
36+
NonStrangeClass.someMethod();
37+
38+
DateTime.now(); // LINT
39+
DateTime.now().day; // LINT
40+
class DateTimeTest {
41+
final currentTimestamp = DateTime.now(); // LINT
42+
}
43+
DateTime currentTimestamp = DateTime('01.01.1959');
3344
```
3445

3546
**✅ Good:**
3647

3748
```dart
3849
myShowDialog();
50+
NonStrangeClass.someMethod();
51+
clock.now();
52+
clock.now().day;
53+
class DateTimeTest {
54+
final currentTimestamp = clock.now();
55+
}
3956
```
4057

4158
### ⚙️ Config example {#config-example}
@@ -53,4 +70,8 @@ dart_code_metrics:
5370
description: The name is too strange
5471
- ident: AnotherStrangeName
5572
description: Oops
73+
- ident: StrangeClass.someMethod
74+
description: Please use a NonStrangeClass.someMethod instead
75+
- ident: DateTime.now
76+
description: Please use a clock.now instead
5677
```

0 commit comments

Comments
 (0)