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

Commit 8676f24

Browse files
authored
feat: add allow-only-once option to no-magic-number rule (#1173)
* feat: add allow-only-once option to no-magic-number * chore: update changelog * fix: after review
1 parent d050514 commit 8676f24

File tree

5 files changed

+48
-1
lines changed

5 files changed

+48
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* fix: export missing parts of public API.
66
* feat: support `context.mounted` for [`use-setstate-synchronously`](https://dcm.dev/docs/individuals/rules/flutter/use-setstate-synchronously).
7+
* feat: add `allow-only-once` option to [`no-magic-number`](https://dcm.dev/docs/individuals/rules/common/no-magic-number).
78

89
## 5.5.0
910

lib/src/analyzers/lint_analyzer/rules/rules_list/no_magic_number/config_parser.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ part of 'no_magic_number_rule.dart';
33
class _ConfigParser {
44
static const _allowedConfigName = 'allowed';
55

6+
static const _allowOnlyOnce = 'allow-only-once';
7+
68
static const _defaultMagicNumbers = [-1, 0, 1];
79

810
static Iterable<num> parseAllowedNumbers(Map<String, Object> config) =>
911
(config[_allowedConfigName] as Iterable?)?.cast<num>() ??
1012
_defaultMagicNumbers;
13+
14+
static bool parseAllowOnlyOnce(Map<String, Object> config) =>
15+
(config[_allowOnlyOnce] as bool?) ?? false;
1116
}

lib/src/analyzers/lint_analyzer/rules/rules_list/no_magic_number/no_magic_number_rule.dart

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ class NoMagicNumberRule extends CommonRule {
2121
'Avoid using magic numbers. Extract them to named constants or variables.';
2222

2323
final Iterable<num> _allowedMagicNumbers;
24+
final bool _allowOnlyOnce;
2425

2526
NoMagicNumberRule([Map<String, Object> config = const {}])
2627
: _allowedMagicNumbers = _ConfigParser.parseAllowedNumbers(config),
28+
_allowOnlyOnce = _ConfigParser.parseAllowOnlyOnce(config),
2729
super(
2830
id: ruleId,
2931
severity: readSeverity(config, Severity.warning),
@@ -45,7 +47,11 @@ class NoMagicNumberRule extends CommonRule {
4547

4648
source.unit.visitChildren(visitor);
4749

48-
return visitor.literals
50+
final literals = _allowOnlyOnce
51+
? _getNotSingleLiterals(visitor.literals)
52+
: visitor.literals;
53+
54+
return literals
4955
.where(_isMagicNumber)
5056
.where(_isNotInsideVariable)
5157
.where(_isNotInsideCollectionLiteral)
@@ -62,6 +68,24 @@ class NoMagicNumberRule extends CommonRule {
6268
.toList(growable: false);
6369
}
6470

71+
Iterable<Literal> _getNotSingleLiterals(Iterable<Literal> literals) {
72+
final literalsCount = <num, int>{};
73+
for (final l in literals) {
74+
if (l is IntegerLiteral) {
75+
final value = l.value;
76+
if (value != null) {
77+
literalsCount.update(value, (count) => ++count, ifAbsent: () => 1);
78+
}
79+
} else if (l is DoubleLiteral) {
80+
literalsCount.update(l.value, (count) => ++count, ifAbsent: () => 1);
81+
}
82+
}
83+
84+
return literals.where((l) =>
85+
l is IntegerLiteral && literalsCount[l.value] != 1 ||
86+
l is DoubleLiteral && literalsCount[l.value] != 1);
87+
}
88+
6589
bool _isMagicNumber(Literal l) =>
6690
(l is DoubleLiteral && !_allowedMagicNumbers.contains(l.value)) ||
6791
(l is IntegerLiteral && !_allowedMagicNumbers.contains(l.value));

test/src/analyzers/lint_analyzer/rules/rules_list/no_magic_number/no_magic_number_rule_test.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ void main() {
6868
RuleTestHelper.verifyNoIssues(issues);
6969
});
7070

71+
test('reports magic numbers used more than once', () async {
72+
final unit = await RuleTestHelper.resolveFromFile(_incorrectExamplePath);
73+
final config = {
74+
'allow-only-once': true,
75+
};
76+
77+
final issues = NoMagicNumberRule(config).check(unit);
78+
79+
RuleTestHelper.verifyIssues(
80+
issues: issues,
81+
startLines: [2, 4],
82+
startColumns: [28, 25],
83+
locationTexts: ['12', '12'],
84+
);
85+
});
86+
7187
test(
7288
'reports magic numbers in objects in widget array structures',
7389
() async {

website/docs/rules/common/no-magic-number.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,5 @@ dart_code_metrics:
5656
...
5757
- no-magic-number:
5858
allowed: [3.14, 100, 12]
59+
allow-only-once: true
5960
```

0 commit comments

Comments
 (0)