From ae5547b15607d1dfe1571cec5d73005644571dd3 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 3 Oct 2022 08:06:10 -0700 Subject: [PATCH 1/2] New rule: no_adjacent_strings_in_collection --- lib/src/rules.dart | 2 + .../no_adjacent_strings_in_collection.dart | 92 ++++++++++++++ test/rules/all.dart | 3 + ...o_adjacent_strings_in_collection_test.dart | 115 ++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 lib/src/rules/no_adjacent_strings_in_collection.dart create mode 100644 test/rules/no_adjacent_strings_in_collection_test.dart diff --git a/lib/src/rules.dart b/lib/src/rules.dart index f127bd3cf..8f1d34a78 100644 --- a/lib/src/rules.dart +++ b/lib/src/rules.dart @@ -91,6 +91,7 @@ import 'rules/lines_longer_than_80_chars.dart'; import 'rules/list_remove_unrelated_type.dart'; import 'rules/literal_only_boolean_expressions.dart'; import 'rules/missing_whitespace_between_adjacent_strings.dart'; +import 'rules/no_adjacent_strings_in_collection.dart'; import 'rules/no_adjacent_strings_in_list.dart'; import 'rules/no_default_cases.dart'; import 'rules/no_duplicate_case_values.dart'; @@ -308,6 +309,7 @@ void registerLintRules({bool inTestMode = false}) { ..register(ListRemoveUnrelatedType()) ..register(LiteralOnlyBooleanExpressions()) ..register(MissingWhitespaceBetweenAdjacentStrings()) + ..register(NoAdjacentStringsInCollection()) ..register(NoAdjacentStringsInList()) ..register(NoDefaultCases()) ..register(NoDuplicateCaseValues()) diff --git a/lib/src/rules/no_adjacent_strings_in_collection.dart b/lib/src/rules/no_adjacent_strings_in_collection.dart new file mode 100644 index 000000000..becd1fefc --- /dev/null +++ b/lib/src/rules/no_adjacent_strings_in_collection.dart @@ -0,0 +1,92 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; + +import '../analyzer.dart'; + +const _desc = r"Don't use adjacent strings in collections."; + +const _details = r''' +**DON'T** use adjacent strings in collections. + +This can indicate a forgotten comma. + +**BAD:** +```dart +List list = [ + 'a' + 'b', + 'c', +]; +``` + +**GOOD:** +```dart +List list = [ + 'a' + + 'b', + 'c', +]; +``` +'''; + +class NoAdjacentStringsInCollection extends LintRule { + NoAdjacentStringsInCollection() + : super( + name: 'no_adjacent_strings_in_collection', + description: _desc, + details: _details, + group: Group.errors); + + @override + void registerNodeProcessors( + NodeLintRegistry registry, LinterContext context) { + var visitor = _Visitor(this); + registry.addForElement(this, visitor); + registry.addIfElement(this, visitor); + registry.addListLiteral(this, visitor); + registry.addSetOrMapLiteral(this, visitor); + } +} + +class _Visitor extends SimpleAstVisitor { + final LintRule rule; + + _Visitor(this.rule); + + @override + void visitForElement(ForElement node) { + if (node.body is AdjacentStrings) { + rule.reportLint(node.body); + } + } + + @override + void visitIfElement(IfElement node) { + if (node.thenElement is AdjacentStrings) { + rule.reportLint(node.thenElement); + } + } + + @override + void visitListLiteral(ListLiteral node) { + for (var e in node.elements) { + if (e is AdjacentStrings) { + rule.reportLint(e); + } + } + } + + @override + void visitSetOrMapLiteral(SetOrMapLiteral node) { + if (node.isMap) return; + for (var e in node.elements) { + if (e is AdjacentStrings) { + rule.reportLint(e); + } + } + } +} diff --git a/test/rules/all.dart b/test/rules/all.dart index 8f437c486..e363be93f 100644 --- a/test/rules/all.dart +++ b/test/rules/all.dart @@ -42,6 +42,8 @@ import 'literal_only_boolean_expressions_test.dart' as literal_only_boolean_expressions; import 'missing_whitespace_between_adjacent_strings_test.dart' as missing_whitespace_between_adjacent_strings; +import 'no_adjacent_strings_in_collection_test.dart' + as no_adjacent_strings_in_collection; import 'non_constant_identifier_names_test.dart' as non_constant_identifier_names; import 'null_closures_test.dart' as null_closures; @@ -116,6 +118,7 @@ void main() { library_private_types_in_public_api.main(); literal_only_boolean_expressions.main(); missing_whitespace_between_adjacent_strings.main(); + no_adjacent_strings_in_collection.main(); non_constant_identifier_names.main(); null_closures.main(); omit_local_variable_types.main(); diff --git a/test/rules/no_adjacent_strings_in_collection_test.dart b/test/rules/no_adjacent_strings_in_collection_test.dart new file mode 100644 index 000000000..25494e3c8 --- /dev/null +++ b/test/rules/no_adjacent_strings_in_collection_test.dart @@ -0,0 +1,115 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../rule_test_support.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(NoAdjacentStringsInCollectionTest); + }); +} + +@reflectiveTest +class NoAdjacentStringsInCollectionTest extends LintRuleTest { + @override + String get lintRule => 'no_adjacent_strings_in_collection'; + + test_adjacent_in_for_element() async { + await assertDiagnostics(''' +var list = [ + for (var _ in []) + 'a' + 'b', + 'c', +]; +''', [ + lint(41, 13), + ]); + } + + test_adjacent_in_if_element() async { + await assertDiagnostics(''' +var list = [ + if (1 == 1) + 'a' + 'b', + 'c', +]; +''', [ + lint(35, 13), + ]); + } + + test_adjacent_in_list() async { + await assertDiagnostics(''' +var list = [ + 'a' + 'b', + 'c', +]; +''', [ + lint(17, 11), + ]); + } + + test_adjacent_in_set() async { + await assertDiagnostics(''' +var list = { + 'a' + 'b', + 'c', +}; +''', [ + lint(17, 11), + ]); + } + + test_no_adjacent_in_for_element() async { + await assertNoDiagnostics(''' +var list = [ + for (var _ in []) + 'a', + 'b', + 'c', +]; +'''); + } + + test_no_adjacent_in_if_element() async { + await assertNoDiagnostics(''' +var list = [ + if (1 == 1) + 'a', + 'b', + 'c', +]; +'''); + } + + test_no_adjacent_in_list() async { + await assertDiagnostics(''' +var list = [ + 'a' + 'b', + 'c', +]; +''', [ + lint(17, 11), + ]); + } + + test_no_adjacent_in_set() async { + await assertDiagnostics(''' +var list = { + 'a' + 'b', + 'c', +}; +''', [ + lint(17, 11), + ]); + } +} From 4a3618c7af746e33911c49dc13f783cd2edc2009 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 3 Oct 2022 09:13:05 -0700 Subject: [PATCH 2/2] all.yaml --- example/all.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/example/all.yaml b/example/all.yaml index 1238f235b..1bc5859d6 100644 --- a/example/all.yaml +++ b/example/all.yaml @@ -88,6 +88,7 @@ linter: - list_remove_unrelated_type - literal_only_boolean_expressions - missing_whitespace_between_adjacent_strings + - no_adjacent_strings_in_collection - no_adjacent_strings_in_list - no_default_cases - no_duplicate_case_values