Skip to content

Commit 3d0f527

Browse files
committed
Add a linter test for duplicate parsers.
1 parent 39c67c7 commit 3d0f527

3 files changed

Lines changed: 48 additions & 2 deletions

File tree

lib/src/reflection/internal/linter_rules.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ class CharacterRepeater extends LinterRule {
4949
}
5050
}
5151

52+
class DuplicateParser extends LinterRule {
53+
const DuplicateParser() : super(LinterType.info, 'Duplicate parser');
54+
55+
@override
56+
void run(Analyzer analyzer, Parser parser, LinterCallback callback) {
57+
final duplicates = analyzer.parsers.where(parser.isEqualTo).toList();
58+
if (duplicates.length > 1 && duplicates.first == parser) {
59+
callback(
60+
LinterIssue(
61+
this,
62+
parser,
63+
'${duplicates.length} instances of the same parser exist in this '
64+
'grammar. If possible, reuse the same parser instances to reduce '
65+
'memory footprint and increase performance.',
66+
),
67+
);
68+
}
69+
}
70+
}
71+
5272
class LeftRecursion extends LinterRule {
5373
const LeftRecursion() : super(LinterType.error, 'Left recursion');
5474

lib/src/reflection/linter.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ typedef LinterCallback = void Function(LinterIssue issue);
6161
/// All default linter rules to be run.
6262
const allLinterRules = [
6363
CharacterRepeater(),
64+
DuplicateParser(),
6465
LeftRecursion(),
6566
NestedChoice(),
6667
NullableRepeater(),

test/reflection_test.dart

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,28 @@ void main() {
717717
expect(results, isEmpty);
718718
});
719719
});
720+
group('duplicate parser', () {
721+
const rules = [linter_rules.DuplicateParser()];
722+
test('with issue', () {
723+
final parser = seq2(digit(), digit());
724+
final results = linter(parser, rules: rules);
725+
expect(results, [
726+
isLinterIssue(
727+
parser: parser.children[0],
728+
type: LinterType.info,
729+
title: 'Duplicate parser',
730+
),
731+
]);
732+
});
733+
test('without issue', () {
734+
final parser = seq2(
735+
digit(message: 'first'),
736+
digit(message: 'second'),
737+
);
738+
final results = linter(parser, rules: rules);
739+
expect(results, isEmpty);
740+
});
741+
});
720742
group('left recursion', () {
721743
const rules = [linter_rules.LeftRecursion()];
722744
test('with issue', () {
@@ -1219,12 +1241,15 @@ void main() {
12191241
group('remove duplicate', () {
12201242
const rules = [optimize_rules.RemoveDuplicate()];
12211243
test('with duplicate', () {
1222-
final parser = lowercase() & lowercase();
1244+
final parser = seq2(digit(), digit());
12231245
final result = optimize(parser, rules: rules);
12241246
expect(result.children.first, same(result.children.last));
12251247
});
12261248
test('without duplicate', () {
1227-
final parser = lowercase() & lowercase(message: 'lower');
1249+
final parser = seq2(
1250+
digit(message: 'first'),
1251+
digit(message: 'second'),
1252+
);
12281253
final result = optimize(
12291254
parser,
12301255
rules: rules,

0 commit comments

Comments
 (0)