From e07775ddf7db4e40314e4dd2a8f67a379fe30a46 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 30 Apr 2024 19:32:36 +0300 Subject: [PATCH 1/7] Create ignored_entities_model; use it for avoid_unused_parameters & avoid_returning_widgets --- .../avoid_returning_widgets_rule.dart | 31 +------- .../avoid_returning_widgets_exclude.dart | 24 ------ .../avoid_returning_widgets_parameters.dart | 28 ------- .../avoid_unused_parameters_rule.dart | 6 +- .../avoid_unused_parameters_visitor.dart | 30 ++++++++ .../ignored_entities_model.dart | 73 +++++++++++++++++++ .../ignored_entity.dart | 25 +++++++ lint_test/analysis_options.yaml | 1 + .../analysis_options.yaml | 12 +++ .../avoid_unused_parameters_test.dart | 10 +++ 10 files changed, 159 insertions(+), 81 deletions(-) delete mode 100644 lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart delete mode 100644 lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart create mode 100644 lib/src/models/ignored_entities_model/ignored_entities_model.dart create mode 100644 lib/src/models/ignored_entities_model/ignored_entity.dart create mode 100644 lint_test/avoid_unused_parameters_test/analysis_options.yaml rename lint_test/{ => avoid_unused_parameters_test}/avoid_unused_parameters_test.dart (96%) diff --git a/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart b/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart index 18d908dd..d03c5e4d 100644 --- a/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart +++ b/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart @@ -1,9 +1,8 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/error/listener.dart'; -import 'package:collection/collection.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; -import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; import 'package:solid_lints/src/models/rule_config.dart'; import 'package:solid_lints/src/models/solid_lint_rule.dart'; import 'package:solid_lints/src/utils/types_utils.dart'; @@ -50,8 +49,7 @@ import 'package:solid_lints/src/utils/types_utils.dart'; /// } /// } /// ``` -class AvoidReturningWidgetsRule - extends SolidLintRule { +class AvoidReturningWidgetsRule extends SolidLintRule { /// The [LintCode] of this lint rule that represents /// the error whether we return a widget. static const lintName = 'avoid_returning_widgets'; @@ -64,7 +62,7 @@ class AvoidReturningWidgetsRule final rule = RuleConfig( configs: configs, name: lintName, - paramsParser: AvoidReturningWidgetsParameters.fromJson, + paramsParser: IgnoredEntitiesModel.fromJson, problemMessage: (_) => 'Returning a widget from a function is considered an anti-pattern. ' 'Unless you are overriding an existing method, ' @@ -96,7 +94,7 @@ class AvoidReturningWidgetsRule final isWidgetReturned = hasWidgetType(returnType); - final isIgnored = _shouldIgnore(node); + final isIgnored = config.parameters.matchMethod(node); final isOverriden = node.declaredElement?.hasOverride ?? false; @@ -105,25 +103,4 @@ class AvoidReturningWidgetsRule } }); } - - bool _shouldIgnore(Declaration node) { - final methodName = node.declaredElement?.name; - - final excludedItem = config.parameters.exclude - .firstWhereOrNull((e) => e.methodName == methodName); - - if (excludedItem == null) return false; - - final className = excludedItem.className; - - if (className == null || node is! MethodDeclaration) { - return true; - } else { - final classDeclaration = node.thisOrAncestorOfType(); - - if (classDeclaration == null) return false; - - return classDeclaration.name.toString() == className; - } - } } diff --git a/lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart b/lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart deleted file mode 100644 index f2cd81be..00000000 --- a/lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart +++ /dev/null @@ -1,24 +0,0 @@ -/// Model class for AvoidReturningWidgetsExclude parameters -class AvoidReturningWidgetsExclude { - /// The name of the method that should be excluded from the lint. - final String methodName; - - /// The name of the class that should be excluded from the lint. - final String? className; - - /// Constructor for [AvoidReturningWidgetsExclude] model - const AvoidReturningWidgetsExclude({ - required this.methodName, - required this.className, - }); - - /// - factory AvoidReturningWidgetsExclude.fromJson( - Map json, - ) { - return AvoidReturningWidgetsExclude( - methodName: json['method_name'] as String, - className: json['class_name'] as String?, - ); - } -} diff --git a/lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart b/lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart deleted file mode 100644 index 75012f5d..00000000 --- a/lib/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart'; - -/// A data model class that represents the "avoid returning widgets" input -/// parameters. -class AvoidReturningWidgetsParameters { - /// A list of methods that should be excluded from the lint. - final List exclude; - - /// Constructor for [AvoidReturningWidgetsParameters] model - AvoidReturningWidgetsParameters({ - required this.exclude, - }); - - /// Method for creating from json data - factory AvoidReturningWidgetsParameters.fromJson(Map json) { - final exclude = []; - - final excludeList = json['exclude'] as Iterable? ?? []; - for (final item in excludeList) { - if (item is Map) { - exclude.add(AvoidReturningWidgetsExclude.fromJson(item)); - } - } - return AvoidReturningWidgetsParameters( - exclude: exclude, - ); - } -} diff --git a/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_rule.dart b/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_rule.dart index be52d0eb..8a713332 100644 --- a/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_rule.dart +++ b/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_rule.dart @@ -1,6 +1,7 @@ import 'package:analyzer/error/listener.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; import 'package:solid_lints/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; import 'package:solid_lints/src/models/rule_config.dart'; import 'package:solid_lints/src/models/solid_lint_rule.dart'; @@ -64,7 +65,7 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// }; /// /// ``` -class AvoidUnusedParametersRule extends SolidLintRule { +class AvoidUnusedParametersRule extends SolidLintRule { /// The [LintCode] of this lint rule that represents /// the error whether we use bad formatted double literals. static const String lintName = 'avoid_unused_parameters'; @@ -79,6 +80,7 @@ class AvoidUnusedParametersRule extends SolidLintRule { final rule = RuleConfig( configs: configs, name: lintName, + paramsParser: IgnoredEntitiesModel.fromJson, problemMessage: (_) => 'Parameter is unused.', ); @@ -92,7 +94,7 @@ class AvoidUnusedParametersRule extends SolidLintRule { CustomLintContext context, ) { context.registry.addCompilationUnit((node) { - final visitor = AvoidUnusedParametersVisitor(); + final visitor = AvoidUnusedParametersVisitor(config.parameters); node.accept(visitor); for (final element in visitor.unusedParameters) { diff --git a/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart b/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart index 40b19f25..5b0e1a0f 100644 --- a/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart +++ b/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart @@ -25,12 +25,19 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:collection/collection.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; import 'package:solid_lints/src/utils/node_utils.dart'; import 'package:solid_lints/src/utils/parameter_utils.dart'; /// AST Visitor which finds all is expressions and checks if they are /// unrelated (result always false) class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { + /// AvoidUnusedParametersVisitor constructor + AvoidUnusedParametersVisitor(this.ignoredEntities); + + /// Entities that should be ignored + final IgnoredEntitiesModel ignoredEntities; + final _unusedParameters = []; /// List of unused parameters @@ -48,6 +55,13 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { parameters.parameters.isEmpty) { return; } + + if (node.thisOrAncestorOfType() case final classNode?) { + if (ignoredEntities.matchClass(classNode)) { + return; + } + } + final unused = _getUnusedParameters( node.body, parameters.parameters, @@ -73,6 +87,16 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } + if (ignoredEntities.matchMethod(node)) { + return; + } + + if (node.thisOrAncestorOfType() case final classNode?) { + if (ignoredEntities.matchClass(classNode)) { + return; + } + } + final isTearOff = _usedAsTearOff(node); if (!isOverride(node.metadata) && !isTearOff) { @@ -93,6 +117,12 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } + if (node.thisOrAncestorOfType() case final funcNode?) { + if (ignoredEntities.matchMethod(funcNode)) { + return; + } + } + _unusedParameters.addAll( _filterOutUnderscoresAndNamed( node.body, diff --git a/lib/src/models/ignored_entities_model/ignored_entities_model.dart b/lib/src/models/ignored_entities_model/ignored_entities_model.dart new file mode 100644 index 00000000..75f5b876 --- /dev/null +++ b/lib/src/models/ignored_entities_model/ignored_entities_model.dart @@ -0,0 +1,73 @@ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entity.dart'; + +/// Manages a list of entities (functions/methods/classes) that should be +/// excluded from a lint rule. +/// +/// Example config: +/// ```yaml +/// custom_lint: +/// rules: +/// - : +/// exclude: +/// # excludes a matching method in a matching class +/// - method_name: excludeMethod +/// class_name: ExcludeClass +/// # excludes a matching method anywhere +/// - method_name: excludeFunction +/// # excludes all methods within a matching class +/// - class_name: ExcludeEntireClass +/// ``` +class IgnoredEntitiesModel { + IgnoredEntitiesModel._({required this.entities}); + + /// + factory IgnoredEntitiesModel.fromJson(Map json) { + final entities = []; + final excludeList = json['exclude'] as Iterable? ?? []; + for (final item in excludeList) { + if (item is Map) { + entities.add(IgnoredEntity.fromJson(item)); + } + } + return IgnoredEntitiesModel._(entities: entities); + } + + /// The entities to be ignored + final List entities; + + /// Checks if the entire class should be ignored. + /// Doesn't match if the config specifies a specific function within the class + bool matchClass(ClassDeclaration node) { + final className = node.name.toString(); + + return entities.any((element) { + return element.functionName == null && element.className == className; + }); + } + + /// Checks if the given method/function should be ignored. + bool matchMethod(Declaration node) { + final methodName = node.declaredElement?.name; + + return entities.any((entity) { + if (entity.functionName != methodName) { + return false; + } + + if (entity.className == null) { + return true; + } + + final matchingClass = node.thisOrAncestorMatching((node) { + if (node case final ClassDeclaration classNode) { + return classNode.name.toString() == entity.className; + } + + return false; + }); + + return matchingClass != null; + }); + } +} diff --git a/lib/src/models/ignored_entities_model/ignored_entity.dart b/lib/src/models/ignored_entities_model/ignored_entity.dart new file mode 100644 index 00000000..f6472064 --- /dev/null +++ b/lib/src/models/ignored_entities_model/ignored_entity.dart @@ -0,0 +1,25 @@ +/// An entity (method/function/class) to be excluded from lint +class IgnoredEntity { + IgnoredEntity._({ + this.className, + this.functionName, + }); + + /// + factory IgnoredEntity.fromJson(Map json) { + return IgnoredEntity._( + className: json['class_name'] as String?, + functionName: json['method_name'] as String?, + ); + } + + /// Class name + final String? className; + /// Function name + final String? functionName; + + @override + String toString() { + return "$className: $functionName"; + } +} diff --git a/lint_test/analysis_options.yaml b/lint_test/analysis_options.yaml index 3d8da192..74e65313 100644 --- a/lint_test/analysis_options.yaml +++ b/lint_test/analysis_options.yaml @@ -3,6 +3,7 @@ analyzer: - custom_lint custom_lint: + debug: true, rules: - cyclomatic_complexity: max_complexity: 4 diff --git a/lint_test/avoid_unused_parameters_test/analysis_options.yaml b/lint_test/avoid_unused_parameters_test/analysis_options.yaml new file mode 100644 index 00000000..9333e0f5 --- /dev/null +++ b/lint_test/avoid_unused_parameters_test/analysis_options.yaml @@ -0,0 +1,12 @@ +analyzer: + plugins: + - ../custom_lint + +custom_lint: + rules: + - avoid_unused_parameters: + exclude: + - method_name: excludeMethod + class_name: ExcludeClass + - method_name: excludeFunction + - class_name: ExcludeEntireClass diff --git a/lint_test/avoid_unused_parameters_test.dart b/lint_test/avoid_unused_parameters_test/avoid_unused_parameters_test.dart similarity index 96% rename from lint_test/avoid_unused_parameters_test.dart rename to lint_test/avoid_unused_parameters_test/avoid_unused_parameters_test.dart index b75e120f..7cba127f 100644 --- a/lint_test/avoid_unused_parameters_test.dart +++ b/lint_test/avoid_unused_parameters_test/avoid_unused_parameters_test.dart @@ -207,3 +207,13 @@ class UsingConstructorParameterInInitializer { print(_value); } } + +class ExcludeEntireClass { + void foo(int a) {} +} + +void excludeFunction(int a, int b) {} + +class ExcludeClass { + void excludeMethod(int a, int b) {} +} From 410a19f41a4472178c83d461983586afaddbf66e Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 May 2024 11:21:32 +0300 Subject: [PATCH 2/7] Add exclude config to the `cyclomatic_complexity` rule --- .../cyclomatic_complexity_rule.dart | 17 ++++++- .../cyclomatic_complexity_parameters.dart | 28 +++++++----- .../max_cyclomatic_complexity_parameters.dart | 21 +++++++++ .../ignored_entities_model.dart | 4 +- .../ignored_entity.dart | 1 + .../analysis_options.yaml | 13 ++++++ .../cyclomatic_complexity_test.dart | 45 +++++++++++++++++++ 7 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 lib/src/lints/cyclomatic_complexity/models/max_cyclomatic_complexity_parameters.dart create mode 100644 lint_test/cyclomatic_complexity/analysis_options.yaml rename lint_test/{ => cyclomatic_complexity}/cyclomatic_complexity_test.dart (50%) diff --git a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart index 86a2570c..62b0e9b8 100644 --- a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart +++ b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/error/listener.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; import 'package:solid_lints/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart'; @@ -39,7 +40,7 @@ class CyclomaticComplexityRule paramsParser: CyclomaticComplexityParameters.fromJson, problemMessage: (value) => 'The maximum allowed complexity of a function is ' - '${value.maxComplexity}. Please decrease it.', + '${value.maxCyclomaticComplexity.maxComplexity}. Please decrease it.', ); return CyclomaticComplexityRule._(rule); @@ -52,11 +53,23 @@ class CyclomaticComplexityRule CustomLintContext context, ) { context.registry.addBlockFunctionBody((node) { + final functionNode = node.thisOrAncestorOfType(); + if (functionNode != null && + config.parameters.ignoredEntities.matchMethod(functionNode)) { + return; + } + + final classNode = node.thisOrAncestorOfType(); + if (classNode != null && + config.parameters.ignoredEntities.matchClass(classNode)) { + return; + } + final visitor = CyclomaticComplexityFlowVisitor(); node.visitChildren(visitor); if (visitor.complexityEntities.length + 1 > - config.parameters.maxComplexity) { + config.parameters.maxCyclomaticComplexity.maxComplexity) { reporter.reportErrorForNode(code, node); } }); diff --git a/lib/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart b/lib/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart index 3ffa5ae1..6166a88b 100644 --- a/lib/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart +++ b/lib/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart @@ -1,19 +1,25 @@ -/// Cyclomatic complexity metric limits configuration. +import 'package:solid_lints/src/lints/cyclomatic_complexity/models/max_cyclomatic_complexity_parameters.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; + +/// Config parameters for the `cyclomatic_complexity` rule class CyclomaticComplexityParameters { - /// Threshold cyclomatic complexity level, exceeding it triggers a warning. - final int maxComplexity; + /// `max_complexity` configuration + final MaxCyclomaticComplexityParameters maxCyclomaticComplexity; - /// Reference: NIST 500-235 item 2.5 - static const _defaultMaxComplexity = 10; + /// `exclude` configuration + final IgnoredEntitiesModel ignoredEntities; /// Constructor for [CyclomaticComplexityParameters] model const CyclomaticComplexityParameters({ - required this.maxComplexity, + required this.maxCyclomaticComplexity, + required this.ignoredEntities, }); - /// Method for creating from json data - factory CyclomaticComplexityParameters.fromJson(Map json) => - CyclomaticComplexityParameters( - maxComplexity: json['max_complexity'] as int? ?? _defaultMaxComplexity, - ); + /// + factory CyclomaticComplexityParameters.fromJson(Map json) { + return CyclomaticComplexityParameters( + ignoredEntities: IgnoredEntitiesModel.fromJson(json), + maxCyclomaticComplexity: MaxCyclomaticComplexityParameters.fromJson(json), + ); + } } diff --git a/lib/src/lints/cyclomatic_complexity/models/max_cyclomatic_complexity_parameters.dart b/lib/src/lints/cyclomatic_complexity/models/max_cyclomatic_complexity_parameters.dart new file mode 100644 index 00000000..237c681f --- /dev/null +++ b/lib/src/lints/cyclomatic_complexity/models/max_cyclomatic_complexity_parameters.dart @@ -0,0 +1,21 @@ +/// Cyclomatic complexity metric limits configuration. +class MaxCyclomaticComplexityParameters { + /// Threshold cyclomatic complexity level, exceeding it triggers a warning. + final int maxComplexity; + + /// Reference: NIST 500-235 item 2.5 + static const _defaultMaxComplexity = 10; + + /// Constructor for [MaxCyclomaticComplexityParameters] model + const MaxCyclomaticComplexityParameters({ + required this.maxComplexity, + }); + + /// Method for creating from json data + factory MaxCyclomaticComplexityParameters.fromJson( + Map json, + ) => + MaxCyclomaticComplexityParameters( + maxComplexity: json['max_complexity'] as int? ?? _defaultMaxComplexity, + ); +} diff --git a/lib/src/models/ignored_entities_model/ignored_entities_model.dart b/lib/src/models/ignored_entities_model/ignored_entities_model.dart index 75f5b876..633a563b 100644 --- a/lib/src/models/ignored_entities_model/ignored_entities_model.dart +++ b/lib/src/models/ignored_entities_model/ignored_entities_model.dart @@ -1,9 +1,9 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:solid_lints/src/models/ignored_entities_model/ignored_entity.dart'; -/// Manages a list of entities (functions/methods/classes) that should be +/// Manages a list of entities (functions/methods/classes) that should be /// excluded from a lint rule. -/// +/// /// Example config: /// ```yaml /// custom_lint: diff --git a/lib/src/models/ignored_entities_model/ignored_entity.dart b/lib/src/models/ignored_entities_model/ignored_entity.dart index f6472064..f182b8ec 100644 --- a/lib/src/models/ignored_entities_model/ignored_entity.dart +++ b/lib/src/models/ignored_entities_model/ignored_entity.dart @@ -15,6 +15,7 @@ class IgnoredEntity { /// Class name final String? className; + /// Function name final String? functionName; diff --git a/lint_test/cyclomatic_complexity/analysis_options.yaml b/lint_test/cyclomatic_complexity/analysis_options.yaml new file mode 100644 index 00000000..8671cb2d --- /dev/null +++ b/lint_test/cyclomatic_complexity/analysis_options.yaml @@ -0,0 +1,13 @@ +analyzer: + plugins: + - ../custom_lint + +custom_lint: + rules: + - cyclomatic_complexity: + max_complexity: 4 + exclude: + - method_name: excludeMethod + class_name: ExcludeClass + - method_name: excludeFunction + - class_name: ExcludeEntireClass diff --git a/lint_test/cyclomatic_complexity_test.dart b/lint_test/cyclomatic_complexity/cyclomatic_complexity_test.dart similarity index 50% rename from lint_test/cyclomatic_complexity_test.dart rename to lint_test/cyclomatic_complexity/cyclomatic_complexity_test.dart index 0fafcdab..33bbd1a4 100644 --- a/lint_test/cyclomatic_complexity_test.dart +++ b/lint_test/cyclomatic_complexity/cyclomatic_complexity_test.dart @@ -31,3 +31,48 @@ class A { if (true) {} } } + +void excludeFunction() { + if (true) { + if (true) { + if (true) { + if (true) {} + } + } + } +} + +class ExcludeEntireClass { + void foo() { + if (true) { + if (true) { + if (true) { + if (true) {} + } + } + } + } +} + +class ExcludeClass { + /// expect_lint: cyclomatic_complexity + void foo() { + if (true) { + if (true) { + if (true) { + if (true) {} + } + } + } + } + + void excludeMethod() { + if (true) { + if (true) { + if (true) { + if (true) {} + } + } + } + } +} From 27ee0660170d813358112d3b4bcf29740b4c22ff Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 May 2024 15:28:41 +0300 Subject: [PATCH 3/7] Implement `exclude` property for the `function_lines_of_code` rule --- .../avoid_returning_widgets_rule.dart | 3 +- .../avoid_unused_parameters_visitor.dart | 20 ++++--------- .../cyclomatic_complexity_rule.dart | 21 ++++++++------ .../function_lines_of_code_rule.dart | 29 +++++++------------ .../function_lines_of_code_parameters.dart | 25 ++++++++-------- .../models/max_lines_parameters.dart | 20 +++++++++++++ .../ignored_entities_model.dart | 20 +++++++++---- .../analysis_options.yaml | 8 +++-- .../function_lines_of_code_test.dart | 17 +++++++++-- 9 files changed, 95 insertions(+), 68 deletions(-) create mode 100644 lib/src/lints/function_lines_of_code/models/max_lines_parameters.dart diff --git a/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart b/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart index d03c5e4d..9f0a54a0 100644 --- a/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart +++ b/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart @@ -94,7 +94,8 @@ class AvoidReturningWidgetsRule extends SolidLintRule { final isWidgetReturned = hasWidgetType(returnType); - final isIgnored = config.parameters.matchMethod(node); + final isIgnored = config.parameters.matchMethod(node) || + config.parameters.matchClass(node); final isOverriden = node.declaredElement?.hasOverride ?? false; diff --git a/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart b/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart index 5b0e1a0f..fe79224d 100644 --- a/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart +++ b/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart @@ -56,10 +56,8 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } - if (node.thisOrAncestorOfType() case final classNode?) { - if (ignoredEntities.matchClass(classNode)) { - return; - } + if (ignoredEntities.matchClass(node)) { + return; } final unused = _getUnusedParameters( @@ -87,16 +85,10 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } - if (ignoredEntities.matchMethod(node)) { + if (ignoredEntities.matchMethod(node) || ignoredEntities.matchClass(node)) { return; } - if (node.thisOrAncestorOfType() case final classNode?) { - if (ignoredEntities.matchClass(classNode)) { - return; - } - } - final isTearOff = _usedAsTearOff(node); if (!isOverride(node.metadata) && !isTearOff) { @@ -117,10 +109,8 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } - if (node.thisOrAncestorOfType() case final funcNode?) { - if (ignoredEntities.matchMethod(funcNode)) { - return; - } + if (ignoredEntities.matchMethod(node)) { + return; } _unusedParameters.addAll( diff --git a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart index 62b0e9b8..a4d4c3b4 100644 --- a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart +++ b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart @@ -1,4 +1,3 @@ -import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/error/listener.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; import 'package:solid_lints/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart'; @@ -53,17 +52,21 @@ class CyclomaticComplexityRule CustomLintContext context, ) { context.registry.addBlockFunctionBody((node) { - final functionNode = node.thisOrAncestorOfType(); - if (functionNode != null && - config.parameters.ignoredEntities.matchMethod(functionNode)) { + if (config.parameters.ignoredEntities.matchMethod(node) || + config.parameters.ignoredEntities.matchClass(node)) { return; } + // final functionNode = node.thisOrAncestorOfType(); + // if (functionNode != null && + // config.parameters.ignoredEntities.matchMethod(functionNode)) { + // return; + // } - final classNode = node.thisOrAncestorOfType(); - if (classNode != null && - config.parameters.ignoredEntities.matchClass(classNode)) { - return; - } + // final classNode = node.thisOrAncestorOfType(); + // if (classNode != null && + // config.parameters.ignoredEntities.matchClass(classNode)) { + // return; + // } final visitor = CyclomaticComplexityFlowVisitor(); node.visitChildren(visitor); diff --git a/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart b/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart index ff90076d..a2abc8ff 100644 --- a/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart +++ b/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart @@ -16,8 +16,11 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// rules: /// - function_lines_of_code: /// max_lines: 100 -/// excludeNames: -/// - "Build" +/// exclude: +/// - method_name: excludeMethod +/// class_name: ExcludeClass +/// - method_name: excludeFunction +/// - class_name: ExcludeEntireClass /// ``` class FunctionLinesOfCodeRule extends SolidLintRule { @@ -35,7 +38,7 @@ class FunctionLinesOfCodeRule name: lintName, paramsParser: FunctionLinesOfCodeParameters.fromJson, problemMessage: (value) => - 'The maximum allowed number of lines is ${value.maxLines}. ' + 'The maximum allowed number of lines is ${value.maxLinesModel}. ' 'Try splitting this function into smaller parts.', ); @@ -60,16 +63,16 @@ class FunctionLinesOfCodeRule ErrorReporter reporter, AstNode node, ) { - final functionName = _getFunctionName(node); - if (functionName != null && - config.parameters.excludeNames.contains(functionName)) { + if (config.parameters.ignoredEntitiesModel.matchMethod(node) || + config.parameters.ignoredEntitiesModel.matchClass(node)) { return; } final visitor = FunctionLinesOfCodeVisitor(resolver.lineInfo); node.visitChildren(visitor); - if (visitor.linesWithCode.length > config.parameters.maxLines) { + if (visitor.linesWithCode.length > + config.parameters.maxLinesModel.maxLines) { if (node is! AnnotatedNode) { return reporter.reportErrorForNode(code, node); } @@ -84,16 +87,4 @@ class FunctionLinesOfCodeRule ); } } - - String? _getFunctionName(AstNode node) { - if (node is FunctionDeclaration) { - return node.name.lexeme; - } else if (node is MethodDeclaration) { - return node.name.lexeme; - } else if (node is FunctionExpression) { - return node.declaredElement?.name; - } else { - return null; - } - } } diff --git a/lib/src/lints/function_lines_of_code/models/function_lines_of_code_parameters.dart b/lib/src/lints/function_lines_of_code/models/function_lines_of_code_parameters.dart index 757f5baf..6852f1c7 100644 --- a/lib/src/lints/function_lines_of_code/models/function_lines_of_code_parameters.dart +++ b/lib/src/lints/function_lines_of_code/models/function_lines_of_code_parameters.dart @@ -1,26 +1,25 @@ -/// A data model class that represents the "function lines of code" input +import 'package:solid_lints/src/lints/function_lines_of_code/models/max_lines_parameters.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; + +/// A data model class that represents the `function_lines_of_code` config /// parameters. class FunctionLinesOfCodeParameters { - /// Maximum allowed number of lines of code (LoC) per function, - /// exceeding this limit triggers a warning. - final int maxLines; - - /// Function names to be excluded from the rule check - final List excludeNames; + /// The `max_lines` configuration + final MaxLinesParameters maxLinesModel; - static const _defaultMaxLines = 200; + /// The `exclude` configuration + final IgnoredEntitiesModel ignoredEntitiesModel; /// Constructor for [FunctionLinesOfCodeParameters] model const FunctionLinesOfCodeParameters({ - required this.maxLines, - required this.excludeNames, + required this.maxLinesModel, + required this.ignoredEntitiesModel, }); /// Method for creating from json data factory FunctionLinesOfCodeParameters.fromJson(Map json) => FunctionLinesOfCodeParameters( - maxLines: json['max_lines'] as int? ?? _defaultMaxLines, - excludeNames: - List.from(json['excludeNames'] as Iterable? ?? []), + maxLinesModel: MaxLinesParameters.fromJson(json), + ignoredEntitiesModel: IgnoredEntitiesModel.fromJson(json), ); } diff --git a/lib/src/lints/function_lines_of_code/models/max_lines_parameters.dart b/lib/src/lints/function_lines_of_code/models/max_lines_parameters.dart new file mode 100644 index 00000000..997e24cc --- /dev/null +++ b/lib/src/lints/function_lines_of_code/models/max_lines_parameters.dart @@ -0,0 +1,20 @@ +/// Data model that represents the limit for the amount of lines within a +/// function. +class MaxLinesParameters { + /// Maximum allowed number of lines of code (LoC) per function, + /// exceeding this limit triggers a warning. + final int maxLines; + + static const _defaultMaxLines = 200; + + /// + const MaxLinesParameters({ + required this.maxLines, + }); + + /// Method for creating from json data + factory MaxLinesParameters.fromJson(Map json) => + MaxLinesParameters( + maxLines: json['max_lines'] as int? ?? _defaultMaxLines, + ); +} diff --git a/lib/src/models/ignored_entities_model/ignored_entities_model.dart b/lib/src/models/ignored_entities_model/ignored_entities_model.dart index 633a563b..3a69ce04 100644 --- a/lib/src/models/ignored_entities_model/ignored_entities_model.dart +++ b/lib/src/models/ignored_entities_model/ignored_entities_model.dart @@ -38,8 +38,13 @@ class IgnoredEntitiesModel { /// Checks if the entire class should be ignored. /// Doesn't match if the config specifies a specific function within the class - bool matchClass(ClassDeclaration node) { - final className = node.name.toString(); + bool matchClass(AstNode node) { + final classNode = node.thisOrAncestorOfType(); + if (classNode == null) { + return false; + } + + final className = classNode.name.toString(); return entities.any((element) { return element.functionName == null && element.className == className; @@ -47,8 +52,13 @@ class IgnoredEntitiesModel { } /// Checks if the given method/function should be ignored. - bool matchMethod(Declaration node) { - final methodName = node.declaredElement?.name; + bool matchMethod(AstNode node) { + final methodNode = node.thisOrAncestorOfType(); + if (methodNode == null) { + return false; + } + + final methodName = methodNode.declaredElement?.name; return entities.any((entity) { if (entity.functionName != methodName) { @@ -59,7 +69,7 @@ class IgnoredEntitiesModel { return true; } - final matchingClass = node.thisOrAncestorMatching((node) { + final matchingClass = methodNode.thisOrAncestorMatching((node) { if (node case final ClassDeclaration classNode) { return classNode.name.toString() == entity.className; } diff --git a/lint_test/function_lines_of_code_test/analysis_options.yaml b/lint_test/function_lines_of_code_test/analysis_options.yaml index 51f88abf..49c25f70 100644 --- a/lint_test/function_lines_of_code_test/analysis_options.yaml +++ b/lint_test/function_lines_of_code_test/analysis_options.yaml @@ -6,6 +6,8 @@ custom_lint: rules: - function_lines_of_code: max_lines: 5 - excludeNames: - - "longFunctionExcluded" - - "longMethodExcluded" + exclude: + - method_name: excludeMethod + class_name: ExcludeClass + - method_name: excludeFunction + - class_name: ExcludeEntireClass \ No newline at end of file diff --git a/lint_test/function_lines_of_code_test/function_lines_of_code_test.dart b/lint_test/function_lines_of_code_test/function_lines_of_code_test.dart index aa4211a9..72fea042 100644 --- a/lint_test/function_lines_of_code_test/function_lines_of_code_test.dart +++ b/lint_test/function_lines_of_code_test/function_lines_of_code_test.dart @@ -1,4 +1,4 @@ -class ClassWithLongMethods { +class ExcludeClass { int notLongMethod() { var i = 0; i++; @@ -18,7 +18,7 @@ class ClassWithLongMethods { } // Excluded by excludeNames - int longMethodExcluded() { + int excludeMethod() { var i = 0; i++; i++; @@ -47,7 +47,7 @@ int longFunction() { } // Excluded by excludeNames -int longFunctionExcluded() { +int excludeFunction() { var i = 0; i++; i++; @@ -55,3 +55,14 @@ int longFunctionExcluded() { i++; return i; } + +class ExcludeEntireClass { + int longFunction() { + var i = 0; + i++; + i++; + i++; + i++; + return i; + } +} From 015f105d51705786426aab90838db54c09fc88a1 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 May 2024 18:04:57 +0300 Subject: [PATCH 4/7] Added `exclude` property to the `no_empty_block` rule. --- .../cyclomatic_complexity_rule.dart | 11 ----------- .../lints/no_empty_block/no_empty_block_rule.dart | 8 ++++++-- .../visitors/no_empty_block_visitor.dart | 11 +++++++++++ .../ignored_entities_model.dart | 3 ++- lint_test/no_empty_block/analysis_options.yaml | 12 ++++++++++++ .../{ => no_empty_block}/no_empty_block_test.dart | 13 +++++++++++++ 6 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 lint_test/no_empty_block/analysis_options.yaml rename lint_test/{ => no_empty_block}/no_empty_block_test.dart (84%) diff --git a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart index a4d4c3b4..1522ba60 100644 --- a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart +++ b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart @@ -56,17 +56,6 @@ class CyclomaticComplexityRule config.parameters.ignoredEntities.matchClass(node)) { return; } - // final functionNode = node.thisOrAncestorOfType(); - // if (functionNode != null && - // config.parameters.ignoredEntities.matchMethod(functionNode)) { - // return; - // } - - // final classNode = node.thisOrAncestorOfType(); - // if (classNode != null && - // config.parameters.ignoredEntities.matchClass(classNode)) { - // return; - // } final visitor = CyclomaticComplexityFlowVisitor(); node.visitChildren(visitor); 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 f083ea77..3eb1971f 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 @@ -1,6 +1,7 @@ import 'package:analyzer/error/listener.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; import 'package:solid_lints/src/lints/no_empty_block/visitors/no_empty_block_visitor.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; import 'package:solid_lints/src/models/rule_config.dart'; import 'package:solid_lints/src/models/solid_lint_rule.dart'; @@ -49,7 +50,7 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// } catch (_) {} // ignored by this rule /// } /// ``` -class NoEmptyBlockRule extends SolidLintRule { +class NoEmptyBlockRule extends SolidLintRule { /// The [LintCode] of this lint rule that represents /// the error whether left empty block. static const String lintName = 'no_empty_block'; @@ -62,6 +63,7 @@ class NoEmptyBlockRule extends SolidLintRule { final config = RuleConfig( configs: configs, name: lintName, + paramsParser: IgnoredEntitiesModel.fromJson, problemMessage: (_) => 'Block is empty. Empty blocks are often indicators of missing code.', ); @@ -76,7 +78,9 @@ class NoEmptyBlockRule extends SolidLintRule { CustomLintContext context, ) { context.registry.addCompilationUnit((node) { - final visitor = NoEmptyBlockVisitor(); + + + final visitor = NoEmptyBlockVisitor(config.parameters); 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..fe497a04 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 @@ -23,17 +23,24 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; const _todoComment = 'TODO'; /// The AST visitor that will find all empty blocks, excluding catch blocks /// and blocks containing [_todoComment] class NoEmptyBlockVisitor extends RecursiveAstVisitor { + /// Entities that this visitor should ignore. + final IgnoredEntitiesModel ignoredEntitiesModel; + final _emptyBlocks = []; /// All empty blocks Iterable get emptyBlocks => _emptyBlocks; + /// + NoEmptyBlockVisitor(this.ignoredEntitiesModel); + @override void visitBlock(Block node) { super.visitBlock(node); @@ -41,6 +48,10 @@ class NoEmptyBlockVisitor extends RecursiveAstVisitor { if (node.statements.isNotEmpty) return; if (node.parent is CatchClause) return; if (_isPrecedingCommentToDo(node)) return; + if (ignoredEntitiesModel.matchClass(node) || + ignoredEntitiesModel.matchMethod(node)) { + return; + } _emptyBlocks.add(node); } diff --git a/lib/src/models/ignored_entities_model/ignored_entities_model.dart b/lib/src/models/ignored_entities_model/ignored_entities_model.dart index 3a69ce04..0ea8971e 100644 --- a/lib/src/models/ignored_entities_model/ignored_entities_model.dart +++ b/lib/src/models/ignored_entities_model/ignored_entities_model.dart @@ -19,7 +19,8 @@ import 'package:solid_lints/src/models/ignored_entities_model/ignored_entity.dar /// - class_name: ExcludeEntireClass /// ``` class IgnoredEntitiesModel { - IgnoredEntitiesModel._({required this.entities}); + /// + const IgnoredEntitiesModel._({required this.entities}); /// factory IgnoredEntitiesModel.fromJson(Map json) { diff --git a/lint_test/no_empty_block/analysis_options.yaml b/lint_test/no_empty_block/analysis_options.yaml new file mode 100644 index 00000000..00919341 --- /dev/null +++ b/lint_test/no_empty_block/analysis_options.yaml @@ -0,0 +1,12 @@ +analyzer: + plugins: + - ../custom_lint + +custom_lint: + rules: + - no_empty_block: + exclude: + - method_name: excludeMethod + class_name: ExcludeClass + - method_name: excludeFunction + - class_name: ExcludeEntireClass diff --git a/lint_test/no_empty_block_test.dart b/lint_test/no_empty_block/no_empty_block_test.dart similarity index 84% rename from lint_test/no_empty_block_test.dart rename to lint_test/no_empty_block/no_empty_block_test.dart index 385d30cb..3d0bc5d6 100644 --- a/lint_test/no_empty_block_test.dart +++ b/lint_test/no_empty_block/no_empty_block_test.dart @@ -49,3 +49,16 @@ class A { // TODO: implement toDoMethod } } + +void excludeFunction() {} + +class ExcludeEntireClass { + void foo() {} +} + +class ExcludeClass { + void excludeMethod() {} + + // expect_lint: no_empty_block + void foo() {} +} From 25c1c77a67d16ad3d36950c51aa6f1fa85b5d2f3 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 May 2024 18:14:36 +0300 Subject: [PATCH 5/7] Added `exclude` configuration to the `number_of_parameters` rule --- .../lints/no_empty_block/no_empty_block_rule.dart | 2 -- .../models/number_of_parameters_parameters.dart | 7 +++++++ .../number_of_parameters_rule.dart | 5 +++++ lint_test/number_of_parameters/analysis_options.yaml | 12 ++++++++++++ .../number_of_parameters_test.dart | 9 +++++++++ 5 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 lint_test/number_of_parameters/analysis_options.yaml rename lint_test/{ => number_of_parameters}/number_of_parameters_test.dart (51%) 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 3eb1971f..da678d29 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 @@ -78,8 +78,6 @@ class NoEmptyBlockRule extends SolidLintRule { CustomLintContext context, ) { context.registry.addCompilationUnit((node) { - - final visitor = NoEmptyBlockVisitor(config.parameters); node.accept(visitor); diff --git a/lib/src/lints/number_of_parameters/models/number_of_parameters_parameters.dart b/lib/src/lints/number_of_parameters/models/number_of_parameters_parameters.dart index e17e63d8..9a99276c 100644 --- a/lib/src/lints/number_of_parameters/models/number_of_parameters_parameters.dart +++ b/lib/src/lints/number_of_parameters/models/number_of_parameters_parameters.dart @@ -1,19 +1,26 @@ +import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart'; + /// A data model class that represents the "number of parameters" input /// parameters. class NumberOfParametersParameters { /// Maximum number of parameters allowed before a warning is triggered. final int maxParameters; + /// The methods/classes that this lint should ignore. + final IgnoredEntitiesModel ignoredEntitiesModel; + static const _defaultMaxParameters = 2; /// Constructor for [NumberOfParametersParameters] model const NumberOfParametersParameters({ required this.maxParameters, + required this.ignoredEntitiesModel, }); /// Method for creating from json data factory NumberOfParametersParameters.fromJson(Map json) => NumberOfParametersParameters( maxParameters: json['max_parameters'] as int? ?? _defaultMaxParameters, + ignoredEntitiesModel: IgnoredEntitiesModel.fromJson(json), ); } diff --git a/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart b/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart index bacc4074..3d5652a0 100644 --- a/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart +++ b/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart @@ -65,6 +65,11 @@ class NumberOfParametersRule CustomLintContext context, ) { context.registry.addDeclaration((node) { + if (config.parameters.ignoredEntitiesModel.matchClass(node) || + config.parameters.ignoredEntitiesModel.matchMethod(node)) { + return; + } + final parameters = switch (node) { (final MethodDeclaration node) => node.parameters?.parameters.length ?? 0, diff --git a/lint_test/number_of_parameters/analysis_options.yaml b/lint_test/number_of_parameters/analysis_options.yaml new file mode 100644 index 00000000..0097e840 --- /dev/null +++ b/lint_test/number_of_parameters/analysis_options.yaml @@ -0,0 +1,12 @@ +analyzer: + plugins: + - ../custom_lint + +custom_lint: + rules: + - number_of_parameters: + exclude: + - method_name: excludeMethod + class_name: ExcludeClass + - method_name: excludeFunction + - class_name: ExcludeEntireClass diff --git a/lint_test/number_of_parameters_test.dart b/lint_test/number_of_parameters/number_of_parameters_test.dart similarity index 51% rename from lint_test/number_of_parameters_test.dart rename to lint_test/number_of_parameters/number_of_parameters_test.dart index 12fa6e21..8d87e4c6 100644 --- a/lint_test/number_of_parameters_test.dart +++ b/lint_test/number_of_parameters/number_of_parameters_test.dart @@ -5,3 +5,12 @@ String numberOfParameters(String a, String b, String c) { return a + b + c; } + +void excludeFunction(int a, int, b, int c) {} + +class ExcludeClass { + // expect_lint: number_of_parameters + void foo(int a, int b, int c) {} + + void excludeMethod(int a, int b, int c) {} +} From 1c321dbc85c7276072e6cce24e7abed265f8c412 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 May 2024 19:06:09 +0300 Subject: [PATCH 6/7] better naming --- .../avoid_returning_widgets_rule.dart | 4 ++-- .../visitors/avoid_unused_parameters_visitor.dart | 7 ++++--- .../cyclomatic_complexity/cyclomatic_complexity_rule.dart | 4 ++-- .../function_lines_of_code_rule.dart | 4 ++-- .../no_empty_block/visitors/no_empty_block_visitor.dart | 4 ++-- .../number_of_parameters/number_of_parameters_rule.dart | 4 ++-- .../ignored_entities_model/ignored_entities_model.dart | 4 ++-- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart b/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart index 9f0a54a0..09ddbb6f 100644 --- a/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart +++ b/lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart @@ -94,8 +94,8 @@ class AvoidReturningWidgetsRule extends SolidLintRule { final isWidgetReturned = hasWidgetType(returnType); - final isIgnored = config.parameters.matchMethod(node) || - config.parameters.matchClass(node); + final isIgnored = config.parameters.isIgnoredMethod(node) || + config.parameters.isIgnoredClass(node); final isOverriden = node.declaredElement?.hasOverride ?? false; diff --git a/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart b/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart index fe79224d..335972e8 100644 --- a/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart +++ b/lib/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart @@ -56,7 +56,7 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } - if (ignoredEntities.matchClass(node)) { + if (ignoredEntities.isIgnoredClass(node)) { return; } @@ -85,7 +85,8 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } - if (ignoredEntities.matchMethod(node) || ignoredEntities.matchClass(node)) { + if (ignoredEntities.isIgnoredMethod(node) || + ignoredEntities.isIgnoredClass(node)) { return; } @@ -109,7 +110,7 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { return; } - if (ignoredEntities.matchMethod(node)) { + if (ignoredEntities.isIgnoredMethod(node)) { return; } diff --git a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart index 1522ba60..7b0feb07 100644 --- a/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart +++ b/lib/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart @@ -52,8 +52,8 @@ class CyclomaticComplexityRule CustomLintContext context, ) { context.registry.addBlockFunctionBody((node) { - if (config.parameters.ignoredEntities.matchMethod(node) || - config.parameters.ignoredEntities.matchClass(node)) { + if (config.parameters.ignoredEntities.isIgnoredMethod(node) || + config.parameters.ignoredEntities.isIgnoredClass(node)) { return; } diff --git a/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart b/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart index a2abc8ff..facc4753 100644 --- a/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart +++ b/lib/src/lints/function_lines_of_code/function_lines_of_code_rule.dart @@ -63,8 +63,8 @@ class FunctionLinesOfCodeRule ErrorReporter reporter, AstNode node, ) { - if (config.parameters.ignoredEntitiesModel.matchMethod(node) || - config.parameters.ignoredEntitiesModel.matchClass(node)) { + if (config.parameters.ignoredEntitiesModel.isIgnoredMethod(node) || + config.parameters.ignoredEntitiesModel.isIgnoredClass(node)) { return; } 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 fe497a04..d1cdc134 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 @@ -48,8 +48,8 @@ class NoEmptyBlockVisitor extends RecursiveAstVisitor { if (node.statements.isNotEmpty) return; if (node.parent is CatchClause) return; if (_isPrecedingCommentToDo(node)) return; - if (ignoredEntitiesModel.matchClass(node) || - ignoredEntitiesModel.matchMethod(node)) { + if (ignoredEntitiesModel.isIgnoredClass(node) || + ignoredEntitiesModel.isIgnoredMethod(node)) { return; } diff --git a/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart b/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart index 3d5652a0..1d318271 100644 --- a/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart +++ b/lib/src/lints/number_of_parameters/number_of_parameters_rule.dart @@ -65,8 +65,8 @@ class NumberOfParametersRule CustomLintContext context, ) { context.registry.addDeclaration((node) { - if (config.parameters.ignoredEntitiesModel.matchClass(node) || - config.parameters.ignoredEntitiesModel.matchMethod(node)) { + if (config.parameters.ignoredEntitiesModel.isIgnoredClass(node) || + config.parameters.ignoredEntitiesModel.isIgnoredMethod(node)) { return; } diff --git a/lib/src/models/ignored_entities_model/ignored_entities_model.dart b/lib/src/models/ignored_entities_model/ignored_entities_model.dart index 0ea8971e..baebafe8 100644 --- a/lib/src/models/ignored_entities_model/ignored_entities_model.dart +++ b/lib/src/models/ignored_entities_model/ignored_entities_model.dart @@ -39,7 +39,7 @@ class IgnoredEntitiesModel { /// Checks if the entire class should be ignored. /// Doesn't match if the config specifies a specific function within the class - bool matchClass(AstNode node) { + bool isIgnoredClass(AstNode node) { final classNode = node.thisOrAncestorOfType(); if (classNode == null) { return false; @@ -53,7 +53,7 @@ class IgnoredEntitiesModel { } /// Checks if the given method/function should be ignored. - bool matchMethod(AstNode node) { + bool isIgnoredMethod(AstNode node) { final methodNode = node.thisOrAncestorOfType(); if (methodNode == null) { return false; From b457d5a100a2a91a6e2efeeb3f744782c38055b7 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 2 May 2024 19:20:21 +0300 Subject: [PATCH 7/7] Edit CHANGELOG --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f95c7c0..ee92b710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ - add quick fix to avoid_final_with_getter (https://github.com/solid-software/solid_lints/pull/164) - 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. +- Consistent `exclude` configuration for the following rules: + - `avoid_returning_widgets` + - `avoid_unused_parameters` + - `cyclomatic_complexity` + - `function_lines_of_code` + - `no_empty_bloc` + - `number_of_parameters` + ## 0.1.5