Skip to content

Commit 348b76a

Browse files
refactor: migrate double_literal_format to analysis_server_plugin
docs: improve code docs
1 parent adfd585 commit 348b76a

8 files changed

Lines changed: 337 additions & 144 deletions

File tree

lib/main.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import 'package:analysis_server_plugin/registry.dart';
33
import 'package:solid_lints/src/lints/avoid_debug_print_in_release/avoid_debug_print_in_release_rule.dart';
44
import 'package:solid_lints/src/lints/avoid_global_state/avoid_global_state_rule.dart';
55
import 'package:solid_lints/src/lints/avoid_non_null_assertion/avoid_non_null_assertion_rule.dart';
6+
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart';
7+
import 'package:solid_lints/src/lints/double_literal_format/fixes/double_literal_format_fix.dart';
68
import 'package:solid_lints/src/lints/proper_super_calls/proper_super_calls_rule.dart';
79

810
/// The entry point for the Solid Lints analyser server plugin.
@@ -33,5 +35,11 @@ class SolidLintsPlugin extends Plugin {
3335
registry.registerLintRule(
3436
ProperSuperCallsRule(),
3537
);
38+
39+
final doubleLiteralFormatRule = DoubleLiteralFormatRule();
40+
registry.registerLintRule(doubleLiteralFormatRule);
41+
for (final code in doubleLiteralFormatRule.diagnosticCodes) {
42+
registry.registerFixForRule(code, DoubleLiteralFormatFix.new);
43+
}
3644
}
3745
}
Lines changed: 85 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
import 'package:analyzer/diagnostic/diagnostic.dart';
2-
import 'package:analyzer/error/listener.dart';
3-
import 'package:analyzer/source/source_range.dart';
4-
import 'package:custom_lint_builder/custom_lint_builder.dart';
5-
import 'package:solid_lints/src/models/rule_config.dart';
6-
import 'package:solid_lints/src/models/solid_lint_rule.dart';
7-
8-
part 'double_literal_format_utils.dart';
9-
part 'fixes/double_literal_format_fix.dart';
1+
import 'package:analyzer/analysis_rule/analysis_rule.dart';
2+
import 'package:analyzer/analysis_rule/rule_context.dart';
3+
import 'package:analyzer/analysis_rule/rule_visitor_registry.dart';
4+
import 'package:analyzer/error/error.dart';
5+
import 'package:solid_lints/src/lints/double_literal_format/visitors/double_literal_format_visitor.dart';
106

117
/// A `double_literal_format` rule which
128
/// checks that double literals should begin with 0. instead of just .,
139
/// and should not end with a trailing 0.
1410
///
11+
/// {@template solid_lints.double_literal_format.example}
1512
/// ### Example
1613
///
1714
/// #### BAD:
@@ -25,75 +22,104 @@ part 'fixes/double_literal_format_fix.dart';
2522
/// ```dart
2623
/// var a = 5.23, b = 0.16e+5, c = -0.25, d = -0.4e-5;
2724
/// ```
28-
class DoubleLiteralFormatRule extends SolidLintRule {
25+
/// {@endtemplate}
26+
class DoubleLiteralFormatRule extends MultiAnalysisRule {
2927
/// This lint rule represents
3028
/// the error whether we use bad formatted double literals.
3129
static const lintName = 'double_literal_format';
3230

3331
// Use different messages for different issues
34-
/// This lint rule represents
35-
/// the error whether we use double literals with a redundant leading 0.
36-
static const _leadingZeroCode = LintCode(
37-
name: lintName,
38-
problemMessage: "Double literals shouldn't have redundant leading `0`.",
32+
/// Reported when the double literal has a redundant leading 0
33+
///
34+
/// ### Example
35+
///
36+
/// #### BAD:
37+
///
38+
/// ```dart
39+
/// var a = 05.23;
40+
/// ```
41+
///
42+
/// #### GOOD:
43+
///
44+
/// ```dart
45+
/// var a = 5.23;
46+
/// ```
47+
static const leadingZeroCode = LintCode(
48+
lintName,
49+
"Double literals shouldn't have redundant leading `0`.",
3950
correctionMessage: "Remove redundant leading `0`.",
51+
uniqueName: 'leadingZero',
4052
);
4153

42-
/// This lint rule represents
43-
/// the error whether we use double literals with a leading decimal point.
44-
static const _leadingDecimalCode = LintCode(
45-
name: lintName,
46-
problemMessage:
47-
"Double literals shouldn't begin with the decimal point `.`.",
54+
/// Reported when the double literal has a leading decimal point
55+
/// without a zero before it.
56+
///
57+
/// ### Example
58+
///
59+
/// #### BAD:
60+
///
61+
/// ```dart
62+
/// var a = .23;
63+
/// ```
64+
///
65+
/// #### GOOD:
66+
///
67+
/// ```dart
68+
/// var a = 0.23;
69+
/// ```
70+
static const leadingDecimalCode = LintCode(
71+
lintName,
72+
"Double literals shouldn't begin with the decimal point `.`.",
4873
correctionMessage: "Add missing leading `0`.",
74+
uniqueName: 'leadingDecimal',
4975
);
5076

51-
/// This lint rule represents
52-
/// the error whether we use double literals with a trailing 0.
53-
static const _trailingZeroCode = LintCode(
54-
name: lintName,
55-
problemMessage: "Double literals should not end with a trailing `0`.",
77+
/// Reported when the double literal has a redundant trailing 0.
78+
///
79+
/// ### Example
80+
///
81+
/// #### BAD:
82+
///
83+
/// ```dart
84+
/// var a = 5.230;
85+
/// ```
86+
///
87+
/// #### GOOD:
88+
///
89+
/// ```dart
90+
/// var a = 5.23;
91+
/// ```
92+
static const trailingZeroCode = LintCode(
93+
lintName,
94+
"Double literals should not end with a trailing `0`.",
5695
correctionMessage: "Remove redundant trailing `0`.",
96+
uniqueName: 'trailingZero',
5797
);
5898

59-
DoubleLiteralFormatRule._(super.config);
99+
@override
100+
List<DiagnosticCode> get diagnosticCodes => [
101+
leadingZeroCode,
102+
leadingDecimalCode,
103+
trailingZeroCode,
104+
];
60105

61106
/// Creates a new instance of [DoubleLiteralFormatRule]
62-
/// based on the lint configuration.
63-
factory DoubleLiteralFormatRule.createRule(CustomLintConfigs configs) {
64-
final rule = RuleConfig(
65-
configs: configs,
66-
name: lintName,
67-
problemMessage: (_) => 'Double literal formatting issue',
68-
);
69-
70-
return DoubleLiteralFormatRule._(rule);
71-
}
107+
DoubleLiteralFormatRule()
108+
: super(
109+
name: lintName,
110+
description:
111+
'Double literals should begin with `0.` instead of just `.`, '
112+
'and should not end with a trailing 0',
113+
);
72114

73115
@override
74-
void run(
75-
CustomLintResolver resolver,
76-
DiagnosticReporter reporter,
77-
CustomLintContext context,
116+
void registerNodeProcessors(
117+
RuleVisitorRegistry registry,
118+
RuleContext context,
78119
) {
79-
context.registry.addDoubleLiteral((node) {
80-
final lexeme = node.literal.lexeme;
120+
super.registerNodeProcessors(registry, context);
81121

82-
if (lexeme.hasLeadingZero) {
83-
reporter.atNode(node, _leadingZeroCode);
84-
return;
85-
}
86-
if (lexeme.hasLeadingDecimalPoint) {
87-
reporter.atNode(node, _leadingDecimalCode);
88-
return;
89-
}
90-
if (lexeme.hasTrailingZero) {
91-
reporter.atNode(node, _trailingZeroCode);
92-
return;
93-
}
94-
});
122+
final visitor = DoubleLiteralFormatVisitor(this);
123+
registry.addDoubleLiteral(this, visitor);
95124
}
96-
97-
@override
98-
List<Fix> getFixes() => [_DoubleLiteralFormatFix()];
99125
}

lib/src/lints/double_literal_format/double_literal_format_utils.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
part of 'double_literal_format_rule.dart';
1+
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart';
22

3-
/// Useful extensions for double literals representation
4-
extension _StringDoubleEx on String {
3+
/// Extension to quickly check double literal formatting according to
4+
/// [DoubleLiteralFormatRule].
5+
extension DoubleLiteralFormatUtils on String {
56
/// Returns true if a double literal starts with 00
67
bool get hasLeadingZero => startsWith('0') && this[1] != '.';
78

Lines changed: 63 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,84 @@
1-
part of '../double_literal_format_rule.dart';
1+
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
2+
import 'package:analysis_server_plugin/edit/dart/dart_fix_kind_priority.dart';
3+
import 'package:analyzer/dart/ast/ast.dart';
4+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
5+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
6+
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart';
7+
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_utils.dart';
28

3-
/// A Quick fix for `double_literal_format` rule
9+
/// A Quick fix for [DoubleLiteralFormatRule] rule
410
/// Suggests the correct value for an issue
5-
class _DoubleLiteralFormatFix extends DartFix {
11+
class DoubleLiteralFormatFix extends ParsedCorrectionProducer {
12+
static const _doubleLiteralFormatKind = FixKind(
13+
'solid_lints.fix.${DoubleLiteralFormatRule.lintName}',
14+
DartFixKindPriority.standard,
15+
"Fix double literal format",
16+
);
17+
18+
/// Creates a new instance of [DoubleLiteralFormatFix].
19+
DoubleLiteralFormatFix({required super.context});
20+
21+
@override
22+
FixKind get fixKind => _doubleLiteralFormatKind;
23+
624
@override
7-
void run(
8-
CustomLintResolver resolver,
9-
ChangeReporter reporter,
10-
CustomLintContext context,
11-
Diagnostic analysisError,
12-
List<Diagnostic> others,
13-
) {
14-
context.registry.addDoubleLiteral((node) {
15-
// checks that the literal declaration is where our warning is located
16-
if (!analysisError.sourceRange.intersects(node.sourceRange)) return;
25+
FixKind get multiFixKind => const FixKind(
26+
'solid_lints.fix.multi.${DoubleLiteralFormatRule.lintName}',
27+
DartFixKindPriority.standard,
28+
"Fix double literal format across files",
29+
);
1730

18-
final lexeme = node.literal.lexeme;
19-
String? correctLexeme;
31+
@override
32+
CorrectionApplicability get applicability =>
33+
CorrectionApplicability.automatically;
34+
35+
@override
36+
Future<void> compute(ChangeBuilder builder) async {
37+
final doubleLiteralNode = node;
38+
if (doubleLiteralNode is! DoubleLiteral) return;
2039

21-
if (lexeme.hasLeadingZero) {
22-
correctLexeme = _correctLeadingZeroLexeme(lexeme);
23-
} else if (lexeme.hasLeadingDecimalPoint) {
24-
correctLexeme = _correctLeadingDecimalPointLexeme(lexeme);
25-
} else if (lexeme.hasTrailingZero) {
26-
correctLexeme = _correctTrailingZeroLexeme(lexeme);
27-
}
40+
final lexeme = doubleLiteralNode.literal.lexeme;
41+
if (!lexeme.hasLeadingZero &&
42+
!lexeme.hasLeadingDecimalPoint &&
43+
!lexeme.hasTrailingZero) {
44+
return;
45+
}
2846

29-
if (correctLexeme != null) {
30-
final changeBuilder = reporter.createChangeBuilder(
31-
message: 'Replace by $correctLexeme',
32-
priority: 1,
33-
);
47+
final correctLexeme = _correctTrailingZeroLexeme(
48+
_correctLeadingZeroLexeme(
49+
_correctLeadingDecimalPointLexeme(
50+
lexeme,
51+
),
52+
),
53+
);
3454

35-
changeBuilder.addDartFileEdit((builder) {
36-
builder.addSimpleReplacement(
37-
SourceRange(node.offset, node.length),
38-
correctLexeme!,
39-
);
40-
});
41-
}
55+
await builder.addDartFileEdit(file, (builder) {
56+
builder.addSimpleReplacement(
57+
doubleLiteralNode.sourceRange,
58+
correctLexeme,
59+
);
4260
});
4361
}
4462

4563
String _correctLeadingZeroLexeme(String lexeme) => !lexeme.hasLeadingZero
4664
? lexeme
4765
: _correctLeadingZeroLexeme(lexeme.substring(1));
4866

49-
String _correctLeadingDecimalPointLexeme(String lexeme) => '0$lexeme';
67+
String _correctLeadingDecimalPointLexeme(String lexeme) =>
68+
lexeme.hasLeadingDecimalPoint ? '0$lexeme' : lexeme;
5069

5170
String _correctTrailingZeroLexeme(String lexeme) {
5271
if (!lexeme.hasTrailingZero) {
5372
return lexeme;
54-
} else {
55-
final mantissa = lexeme.split('e').first;
56-
return _correctTrailingZeroLexeme(
57-
lexeme.replaceFirst(
58-
mantissa,
59-
mantissa.substring(0, mantissa.length - 1),
60-
),
61-
);
6273
}
74+
75+
final mantissa = lexeme.split('e').first;
76+
77+
return _correctTrailingZeroLexeme(
78+
lexeme.replaceFirst(
79+
mantissa,
80+
mantissa.substring(0, mantissa.length - 1),
81+
),
82+
);
6383
}
6484
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import 'package:analyzer/dart/ast/ast.dart';
2+
import 'package:analyzer/dart/ast/visitor.dart';
3+
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart'
4+
show DoubleLiteralFormatRule;
5+
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_utils.dart';
6+
7+
/// A visitor that checks that double literals are formatted according to
8+
/// [DoubleLiteralFormatRule].
9+
/// {@macro solid_lints.double_literal_format.example}
10+
class DoubleLiteralFormatVisitor extends SimpleAstVisitor<void> {
11+
final DoubleLiteralFormatRule _rule;
12+
13+
/// Creates a new instance of [DoubleLiteralFormatVisitor].
14+
DoubleLiteralFormatVisitor(this._rule);
15+
16+
@override
17+
void visitDoubleLiteral(DoubleLiteral node) {
18+
super.visitDoubleLiteral(node);
19+
20+
final lexeme = node.literal.lexeme;
21+
22+
if (lexeme.hasLeadingZero) {
23+
_rule.reportAtNode(
24+
node,
25+
diagnosticCode: DoubleLiteralFormatRule.leadingZeroCode,
26+
);
27+
return;
28+
}
29+
30+
if (lexeme.hasLeadingDecimalPoint) {
31+
_rule.reportAtNode(
32+
node,
33+
diagnosticCode: DoubleLiteralFormatRule.leadingDecimalCode,
34+
);
35+
return;
36+
}
37+
38+
if (lexeme.hasTrailingZero) {
39+
_rule.reportAtNode(
40+
node,
41+
diagnosticCode: DoubleLiteralFormatRule.trailingZeroCode,
42+
);
43+
return;
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)