diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e806260..4fdab793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.0 + +- Added `allow_with_comments` parameter for `no_empty_block` lint. + ## 0.3.0 - Added `exclude` parameter for the following lints: @@ -30,11 +34,11 @@ ## 0.2.0 - Added `avoid_final_with_getter` rule -- Improve `avoid_late_keyword` - `ignored_types` to support ignoring subtype of the node type (https://github.com/solid-software/solid_lints/issues/157) -- Abstract methods should be omitted by `proper_super_calls` (https://github.com/solid-software/solid_lints/issues/159) -- Add a rule prefer_guard_clause for reversing nested if statements (https://github.com/solid-software/solid_lints/issues/91) -- add exclude params support to avoid_returning_widgets rule (https://github.com/solid-software/solid_lints/issues/131) -- add quick fix to avoid_final_with_getter (https://github.com/solid-software/solid_lints/pull/164) +- Improve `avoid_late_keyword` - `ignored_types` to support ignoring subtype of the node type () +- Abstract methods should be omitted by `proper_super_calls` () +- Add a rule prefer_guard_clause for reversing nested if statements () +- add exclude params support to avoid_returning_widgets rule () +- add quick fix to avoid_final_with_getter () - Renamed `avoid_debug_print` to `avoid_debug_print_in_release` - The `avoid_debug_print_in_release` no longer reports a warning if the `debugPrint` call is wrapped in a `!kReleaseMode` check. - Update custom_lints to work with newer Flutter @@ -50,8 +54,8 @@ - Fixed unexpected avoid_unnecessary_type_assertions - Added `excludeNames` param for `function_lines_of_code` lint - Improved `avoid_unrelated_type_assertions` to support true and false results -- Set default `cyclomatic_complexity` to 10 (https://github.com/solid-software/solid_lints/issues/146) - Credits: Arthur Miranda (https://github.com/arthurbcd) +- Set default `cyclomatic_complexity` to 10 () + Credits: Arthur Miranda () ## 0.1.4 @@ -86,7 +90,7 @@ - avoid_unrelated_type_assertions - avoid_unused_parameters - avoid_using_api - Credits: getBoolean (https://github.com/getBoolean) + Credits: getBoolean () - cyclomatic_complexity - double_literal_format - function_lines_of_code diff --git a/lib/src/lints/no_empty_block/models/no_empty_block_parameters.dart b/lib/src/lints/no_empty_block/models/no_empty_block_parameters.dart index 42f1eb44..d8e143f3 100644 --- a/lib/src/lints/no_empty_block/models/no_empty_block_parameters.dart +++ b/lib/src/lints/no_empty_block/models/no_empty_block_parameters.dart @@ -3,18 +3,25 @@ import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_para /// A data model class that represents the "no empty block" lint input /// parameters. class NoEmptyBlockParameters { + static const _allowWithCommentsConfig = 'allow_with_comments'; + /// A list of methods that should be excluded from the lint. final ExcludedIdentifiersListParameter exclude; + /// Whether to exclude empty blocks that contain any comments. + final bool allowWithComments; + /// Constructor for [NoEmptyBlockParameters] model NoEmptyBlockParameters({ required this.exclude, + required this.allowWithComments, }); /// Method for creating from json data factory NoEmptyBlockParameters.fromJson(Map json) { return NoEmptyBlockParameters( exclude: ExcludedIdentifiersListParameter.defaultFromJson(json), + allowWithComments: json[_allowWithCommentsConfig] as bool? ?? false, ); } } diff --git a/lib/src/lints/no_empty_block/no_empty_block_rule.dart b/lib/src/lints/no_empty_block/no_empty_block_rule.dart index a30576f4..546e0eac 100644 --- a/lib/src/lints/no_empty_block/no_empty_block_rule.dart +++ b/lib/src/lints/no_empty_block/no_empty_block_rule.dart @@ -81,7 +81,9 @@ class NoEmptyBlockRule extends SolidLintRule { final isIgnored = config.parameters.exclude.shouldIgnore(node); if (isIgnored) return; - final visitor = NoEmptyBlockVisitor(); + final visitor = NoEmptyBlockVisitor( + allowWithComments: config.parameters.allowWithComments, + ); node.accept(visitor); for (final emptyBlock in visitor.emptyBlocks) { diff --git a/lib/src/lints/no_empty_block/visitors/no_empty_block_visitor.dart b/lib/src/lints/no_empty_block/visitors/no_empty_block_visitor.dart index 3248f3bd..3f1e50d3 100644 --- a/lib/src/lints/no_empty_block/visitors/no_empty_block_visitor.dart +++ b/lib/src/lints/no_empty_block/visitors/no_empty_block_visitor.dart @@ -29,8 +29,16 @@ const _todoComment = 'TODO'; /// The AST visitor that will find all empty blocks, excluding catch blocks /// and blocks containing [_todoComment] class NoEmptyBlockVisitor extends RecursiveAstVisitor { + final bool _allowWithComments; + final _emptyBlocks = []; + /// Constructor for [NoEmptyBlockVisitor] + /// [_allowWithComments] indicates whether to allow empty blocks that contain + /// any comments + NoEmptyBlockVisitor({required bool allowWithComments}) + : _allowWithComments = allowWithComments; + /// All empty blocks Iterable get emptyBlocks => _emptyBlocks; @@ -40,6 +48,7 @@ class NoEmptyBlockVisitor extends RecursiveAstVisitor { if (node.statements.isNotEmpty) return; if (node.parent is CatchClause) return; + if (_allowWithComments && _isPrecedingCommentAny(node)) return; if (_isPrecedingCommentToDo(node)) return; _emptyBlocks.add(node); @@ -47,4 +56,7 @@ class NoEmptyBlockVisitor extends RecursiveAstVisitor { static bool _isPrecedingCommentToDo(Block node) => node.endToken.precedingComments?.lexeme.contains(_todoComment) ?? false; + + static bool _isPrecedingCommentAny(Block node) => + node.endToken.precedingComments != null; } diff --git a/lint_test/analysis_options.yaml b/lint_test/analysis_options.yaml index e5a001c3..94fdbefb 100644 --- a/lint_test/analysis_options.yaml +++ b/lint_test/analysis_options.yaml @@ -9,7 +9,7 @@ custom_lint: exclude: - class_name: Exclude method_name: excludeMethod - - method_name: excludeMethod + - method_name: excludeMethod - number_of_parameters: max_parameters: 2 exclude: @@ -24,7 +24,7 @@ custom_lint: - avoid_global_state - avoid_returning_widgets: exclude: - - class_name: ExcludeWidget + - class_name: ExcludeWidget method_name: excludeWidgetMethod - method_name: excludeMethod - avoid_unnecessary_setstate @@ -34,7 +34,7 @@ custom_lint: - avoid_unrelated_type_assertions - avoid_unused_parameters: exclude: - - class_name: Exclude + - class_name: Exclude method_name: excludeMethod - method_name: excludeMethod - simpleMethodName @@ -42,8 +42,9 @@ custom_lint: - exclude - newline_before_return - no_empty_block: + allow_with_comments: true exclude: - - class_name: Exclude + - class_name: Exclude method_name: excludeMethod - method_name: excludeMethod - no_equal_then_else diff --git a/lint_test/no_empty_block_test.dart b/lint_test/no_empty_block_test.dart index 96f2ef0d..793dd031 100644 --- a/lint_test/no_empty_block_test.dart +++ b/lint_test/no_empty_block_test.dart @@ -57,3 +57,26 @@ class Exclude { // no lint void excludeMethod() {} } + +// no lint +void emptyMethodWithComments() { + // comment explaining why this block is empty +} + +void anotherExample() { + // no lint + nestedFun(() { + // explain why this block is empty + }); +} + +void nestedIfElse() { + if (true) { + if (true) { + // no lint + if (true) { + // explain why this block is empty + } + } + } +}