Skip to content

Commit b40bee6

Browse files
author
Illia Aihistov
committed
refactor: migrate no_magic_number rule
1 parent c6cd0b2 commit b40bee6

6 files changed

Lines changed: 455 additions & 214 deletions

File tree

lib/main.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:solid_lints/src/lints/cyclomatic_complexity/cyclomatic_complexit
1414
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart';
1515
import 'package:solid_lints/src/lints/double_literal_format/fixes/double_literal_format_fix.dart';
1616
import 'package:solid_lints/src/lints/function_lines_of_code/function_lines_of_code_rule.dart';
17+
import 'package:solid_lints/src/lints/no_magic_number/no_magic_number_rule.dart';
1718
import 'package:solid_lints/src/lints/prefer_first/fixes/prefer_first_fix.dart';
1819
import 'package:solid_lints/src/lints/prefer_first/prefer_first_rule.dart';
1920
import 'package:solid_lints/src/lints/proper_super_calls/proper_super_calls_rule.dart';
@@ -65,6 +66,9 @@ class SolidLintsPlugin extends Plugin {
6566
),
6667
UseNearestContextRule(),
6768
preferFirstRule,
69+
NoMagicNumberRule(
70+
analysisOptionsLoader: analysisLoader,
71+
),
6872
// TODO: Add more lint rules and use analysisLoader
6973
// for rules that need parameters
7074
// For example: `CyclomaticComplexityRule(analysisLoader)`

lib/src/lints/no_magic_number/models/no_magic_number_parameters.dart

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,23 @@ class NoMagicNumberParameters {
4747
required this.allowedInWidgetParams,
4848
});
4949

50-
/// Method for creating from json data
51-
factory NoMagicNumberParameters.fromJson(Map<String, Object?> json) =>
52-
NoMagicNumberParameters(
53-
allowedNumbers:
54-
json[_allowedConfigName] as Iterable<num>? ?? _defaultMagicNumbers,
55-
allowedInWidgetParams:
56-
json[_allowedInWidgetParamsConfigName] as bool? ?? false,
50+
/// Creates an empty/default instance of [NoMagicNumberParameters]
51+
factory NoMagicNumberParameters.empty() => const NoMagicNumberParameters(
52+
allowedNumbers: _defaultMagicNumbers,
53+
allowedInWidgetParams: false,
5754
);
55+
56+
/// Method for creating from json data
57+
factory NoMagicNumberParameters.fromJson(Map<String, Object?> json) {
58+
final allowedRaw = json[_allowedConfigName];
59+
final allowedList = allowedRaw is Iterable
60+
? allowedRaw.whereType<num>().toList()
61+
: _defaultMagicNumbers;
62+
63+
return NoMagicNumberParameters(
64+
allowedNumbers: allowedList,
65+
allowedInWidgetParams:
66+
json[_allowedInWidgetParamsConfigName] as bool? ?? false,
67+
);
68+
}
5869
}
Lines changed: 34 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,8 @@
1-
// MIT License
2-
//
3-
// Copyright (c) 2020-2021 Dart Code Checker team
4-
//
5-
// Permission is hereby granted, free of charge, to any person obtaining a copy
6-
// of this software and associated documentation files (the "Software"), to deal
7-
// in the Software without restriction, including without limitation the rights
8-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
// copies of the Software, and to permit persons to whom the Software is
10-
// furnished to do so, subject to the following conditions:
11-
//
12-
// The above copyright notice and this permission notice shall be included in
13-
// all
14-
// copies or substantial portions of the Software.
15-
//
16-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22-
// SOFTWARE.
23-
24-
import 'package:analyzer/dart/ast/ast.dart';
25-
import 'package:analyzer/dart/element/type.dart';
26-
import 'package:analyzer/error/listener.dart';
27-
import 'package:collection/collection.dart';
28-
import 'package:custom_lint_builder/custom_lint_builder.dart';
1+
import 'package:analyzer/analysis_rule/rule_context.dart';
2+
import 'package:analyzer/analysis_rule/rule_visitor_registry.dart';
3+
import 'package:analyzer/error/error.dart';
294
import 'package:solid_lints/src/lints/no_magic_number/models/no_magic_number_parameters.dart';
30-
import 'package:solid_lints/src/lints/no_magic_number/visitors/no_magic_number_visitor.dart';
31-
import 'package:solid_lints/src/models/rule_config.dart';
5+
import 'package:solid_lints/src/lints/no_magic_number/visitors/no_magic_number_rule_visitor.dart';
326
import 'package:solid_lints/src/models/solid_lint_rule.dart';
337

348
/// A `no_magic_number` rule which forbids having numbers without variable
@@ -43,11 +17,12 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart';
4317
/// ### Example config:
4418
///
4519
/// ```yaml
46-
/// custom_lint:
47-
/// rules:
48-
/// - no_magic_number:
49-
/// allowed: [12, 42]
50-
/// allowed_in_widget_params: true
20+
/// plugins:
21+
/// solid_lints:
22+
/// diagnostics:
23+
/// no_magic_number:
24+
/// allowed: [12, 42]
25+
/// allowed_in_widget_params: true
5126
/// ```
5227
///
5328
/// ### Example
@@ -88,7 +63,7 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart';
8863
/// const Circle({required this.r});
8964
/// }
9065
/// const Circle(r: 5);
91-
/// const circle = Circle(r: 10)
66+
/// const circle = Circle(r: 10);
9267
/// ```
9368
///
9469
/// ### Allowed
@@ -138,139 +113,36 @@ class NoMagicNumberRule extends SolidLintRule<NoMagicNumberParameters> {
138113
/// the error when having magic number.
139114
static const String lintName = 'no_magic_number';
140115

141-
NoMagicNumberRule._(super.config);
142-
143-
/// Creates a new instance of [NoMagicNumberRule]
144-
/// based on the lint configuration.
145-
factory NoMagicNumberRule.createRule(CustomLintConfigs configs) {
146-
final config = RuleConfig<NoMagicNumberParameters>(
147-
configs: configs,
148-
name: lintName,
149-
paramsParser: NoMagicNumberParameters.fromJson,
150-
problemMessage: (_) => 'Avoid using magic numbers.'
151-
'Extract them to named constants or variables.',
152-
);
153-
154-
return NoMagicNumberRule._(config);
155-
}
116+
static const _code = LintCode(
117+
lintName,
118+
'Avoid using magic numbers. Extract them to named constants or variables.',
119+
);
156120

157121
@override
158-
void run(
159-
CustomLintResolver resolver,
160-
DiagnosticReporter reporter,
161-
CustomLintContext context,
162-
) {
163-
context.registry.addCompilationUnit((node) {
164-
final visitor = NoMagicNumberVisitor();
165-
node.accept(visitor);
166-
167-
final magicNumbers = visitor.literals
168-
.where(_isMagicNumber)
169-
.where(_isNotInsideVariable)
170-
.where(_isNotInsideCollectionLiteral)
171-
.where(_isNotInsideConstMap)
172-
.where(_isNotInsideConstConstructor)
173-
.where(_isNotInDateTime)
174-
.where(_isNotInsideIndexExpression)
175-
.where(_isNotInsideEnumConstantArguments)
176-
.where(_isNotDefaultValue)
177-
.where(_isNotInConstructorInitializer)
178-
.where(_isNotWidgetParameter);
179-
180-
for (final magicNumber in magicNumbers) {
181-
reporter.atNode(magicNumber, code);
182-
}
183-
});
184-
}
185-
186-
bool _isMagicNumber(Literal l) =>
187-
(l is DoubleLiteral &&
188-
!config.parameters.allowedNumbers.contains(l.value)) ||
189-
(l is IntegerLiteral &&
190-
!config.parameters.allowedNumbers.contains(l.value));
191-
192-
bool _isNotInsideVariable(Literal l) {
193-
// Whether we encountered such node,
194-
// This is tracked because [InstanceCreationExpression] can be
195-
// inside [VariableDeclaration] removing unwanted literals
196-
197-
bool isInstanceCreationExpression = false;
198-
return l.thisOrAncestorMatching((ancestor) {
199-
if (ancestor is InstanceCreationExpression) {
200-
isInstanceCreationExpression = true;
201-
}
202-
if (isInstanceCreationExpression) {
203-
return false;
204-
} else {
205-
return ancestor is VariableDeclaration;
206-
}
207-
}) ==
208-
null;
209-
}
210-
211-
bool _isNotInDateTime(Literal l) =>
212-
l.thisOrAncestorMatching(
213-
(a) =>
214-
a is InstanceCreationExpression &&
215-
a.staticType?.getDisplayString() == 'DateTime',
216-
) ==
217-
null;
218-
219-
bool _isNotInsideEnumConstantArguments(Literal l) {
220-
final node = l.thisOrAncestorMatching(
221-
(ancestor) => ancestor is EnumConstantArguments,
222-
);
223-
224-
return node == null;
225-
}
122+
DiagnosticCode get diagnosticCode => _code;
226123

227-
bool _isNotInsideCollectionLiteral(Literal l) => l.parent is! TypedLiteral;
228-
229-
bool _isNotInsideConstMap(Literal l) {
230-
final grandParent = l.parent?.parent;
231-
232-
return !(grandParent is SetOrMapLiteral && grandParent.isConst);
233-
}
234-
235-
bool _isNotInsideConstConstructor(Literal l) =>
236-
l.thisOrAncestorMatching((ancestor) {
237-
return ancestor is InstanceCreationExpression && ancestor.isConst;
238-
}) ==
239-
null;
240-
241-
bool _isNotInsideIndexExpression(Literal l) => l.parent is! IndexExpression;
242-
243-
bool _isNotDefaultValue(Literal literal) {
244-
return literal.thisOrAncestorOfType<DefaultFormalParameter>() == null;
245-
}
246-
247-
bool _isNotInConstructorInitializer(Literal literal) {
248-
return literal.thisOrAncestorOfType<ConstructorInitializer>() == null;
249-
}
250-
251-
bool _isNotWidgetParameter(Literal literal) {
252-
if (!config.parameters.allowedInWidgetParams) return true;
253-
254-
final widgetCreationExpression = literal.thisOrAncestorMatching(
255-
_isWidgetCreationExpression,
256-
);
257-
258-
return widgetCreationExpression == null;
259-
}
124+
/// Creates a new instance of [NoMagicNumberRule]
125+
NoMagicNumberRule({
126+
required super.analysisOptionsLoader,
127+
}) : super.withParameters(
128+
name: lintName,
129+
description: 'Forbids having numbers without variable.',
130+
parametersParser: NoMagicNumberParameters.fromJson,
131+
);
260132

261-
bool _isWidgetCreationExpression(
262-
AstNode node,
133+
@override
134+
void registerNodeProcessors(
135+
RuleVisitorRegistry registry,
136+
RuleContext context,
263137
) {
264-
if (node is! InstanceCreationExpression) return false;
265-
266-
final staticType = node.staticType;
138+
super.registerNodeProcessors(registry, context);
267139

268-
if (staticType is! InterfaceType) return false;
140+
final parameters =
141+
getParametersForContext(context) ?? NoMagicNumberParameters.empty();
269142

270-
final widgetSupertype = staticType.allSupertypes.firstWhereOrNull(
271-
(supertype) => supertype.getDisplayString() == 'Widget',
272-
);
143+
final visitor = NoMagicNumberRuleVisitor(this, parameters);
273144

274-
return widgetSupertype != null;
145+
registry.addDoubleLiteral(this, visitor);
146+
registry.addIntegerLiteral(this, visitor);
275147
}
276148
}

0 commit comments

Comments
 (0)