From 36d9ca172505ebff5b92370e995b9ca3994fe2c5 Mon Sep 17 00:00:00 2001 From: xJac0b Date: Fri, 6 Jun 2025 14:58:36 +0200 Subject: [PATCH 01/11] feat: add new rule use_descriptive_names_for_type_parameters --- ...iptive_names_for_type_parameters_rule.dart | 84 +++++++++++++++++++ ...ive_names_for_type_parameters_visitor.dart | 60 +++++++++++++ .../analysis_options.yaml | 3 + ...iptive_names_for_type_parameters_test.dart | 45 ++++++++++ 4 files changed, 192 insertions(+) create mode 100644 lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart create mode 100644 lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart create mode 100644 lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml create mode 100644 lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart new file mode 100644 index 00000000..e9735fe7 --- /dev/null +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -0,0 +1,84 @@ +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/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart'; +import 'package:solid_lints/src/models/rule_config.dart'; +import 'package:solid_lints/src/models/solid_lint_rule.dart'; + +/// A `use_descriptive_names_for_type_parameters` rule which +/// warns about single-letter type parameter names when there are +/// three or more type parameters. +class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { + /// The lint rule name. + static const lintName = 'use_descriptive_names_for_type_parameters'; + + UseDescriptiveNamesForTypeParametersRule._(super.config); + + /// Creates a new instance of [UseDescriptiveNamesForTypeParametersRule] + /// based on the lint configuration. + factory UseDescriptiveNamesForTypeParametersRule.createRule( + CustomLintConfigs configs, + ) { + final rule = RuleConfig( + configs: configs, + name: lintName, + problemMessage: (_) => + 'Type parameters should have descriptive names instead ' + 'of single letters when there are three or more type parameters.', + ); + + return UseDescriptiveNamesForTypeParametersRule._(rule); + } + + @override + void run( + CustomLintResolver resolver, + ErrorReporter reporter, + CustomLintContext context, + ) { + context.registry.addClassDeclaration((node) { + final visitor = UseDescriptiveNamesForTypeParametersVisitor(); + visitor.visitClassDeclaration(node); + _reportViolations(reporter, visitor.singleLetterTypeParameters); + }); + + context.registry.addFunctionDeclaration((node) { + final visitor = UseDescriptiveNamesForTypeParametersVisitor(); + visitor.visitFunctionDeclaration(node); + _reportViolations(reporter, visitor.singleLetterTypeParameters); + }); + + context.registry.addMethodDeclaration((node) { + final visitor = UseDescriptiveNamesForTypeParametersVisitor(); + visitor.visitMethodDeclaration(node); + _reportViolations(reporter, visitor.singleLetterTypeParameters); + }); + + context.registry.addGenericTypeAlias((node) { + final visitor = UseDescriptiveNamesForTypeParametersVisitor(); + visitor.visitGenericTypeAlias(node); + _reportViolations(reporter, visitor.singleLetterTypeParameters); + }); + + context.registry.addExtensionDeclaration((node) { + final visitor = UseDescriptiveNamesForTypeParametersVisitor(); + visitor.visitExtensionDeclaration(node); + _reportViolations(reporter, visitor.singleLetterTypeParameters); + }); + + context.registry.addMixinDeclaration((node) { + final visitor = UseDescriptiveNamesForTypeParametersVisitor(); + visitor.visitMixinDeclaration(node); + _reportViolations(reporter, visitor.singleLetterTypeParameters); + }); + } + + void _reportViolations( + ErrorReporter reporter, + List singleLetterTypeParameters, + ) { + for (final param in singleLetterTypeParameters) { + reporter.atNode(param, code); + } + } +} diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart new file mode 100644 index 00000000..f1d2ff5f --- /dev/null +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart @@ -0,0 +1,60 @@ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; + +/// AST Visitor which finds type parameters with single-letter names +/// in declarations with three or more type parameters. +class UseDescriptiveNamesForTypeParametersVisitor + extends RecursiveAstVisitor { + /// List of type parameters with single-letter names. + final singleLetterTypeParameters = []; + + @override + void visitClassDeclaration(ClassDeclaration node) { + super.visitClassDeclaration(node); + _checkTypeParameters(node.typeParameters); + } + + @override + void visitFunctionDeclaration(FunctionDeclaration node) { + super.visitFunctionDeclaration(node); + final function = node.functionExpression; + _checkTypeParameters(function.typeParameters); + } + + @override + void visitMethodDeclaration(MethodDeclaration node) { + super.visitMethodDeclaration(node); + _checkTypeParameters(node.typeParameters); + } + + @override + void visitGenericTypeAlias(GenericTypeAlias node) { + super.visitGenericTypeAlias(node); + _checkTypeParameters(node.typeParameters); + } + + @override + void visitExtensionDeclaration(ExtensionDeclaration node) { + super.visitExtensionDeclaration(node); + _checkTypeParameters(node.typeParameters); + } + + @override + void visitMixinDeclaration(MixinDeclaration node) { + super.visitMixinDeclaration(node); + _checkTypeParameters(node.typeParameters); + } + + void _checkTypeParameters(TypeParameterList? typeParameters) { + if (typeParameters == null || typeParameters.typeParameters.length < 3) { + return; + } + + for (final param in typeParameters.typeParameters) { + final name = param.name.lexeme; + if (name.length == 1) { + singleLetterTypeParameters.add(param); + } + } + } +} diff --git a/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml b/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml new file mode 100644 index 00000000..852d28aa --- /dev/null +++ b/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml @@ -0,0 +1,3 @@ +custom_lint: + rules: + - use_descriptive_names_for_type_parameters diff --git a/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart b/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart new file mode 100644 index 00000000..84ad85c3 --- /dev/null +++ b/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart @@ -0,0 +1,45 @@ +/// Check the `use_descriptive_names_for_type_parameters` rule + +// expect_lint: use_descriptive_names_for_type_parameters +class SomeClass {} + +class ValidClass {} + +class TwoParams {} + +// expect_lint: use_descriptive_names_for_type_parameters +class AnotherClass {} + +// expect_lint: use_descriptive_names_for_type_parameters +void functionWithTypes(T t, U u, K k) {} + +void validFunction(Type t, Data d, Context c) {} + +void twoTypeParams(T t, U u) {} + +// expect_lint: use_descriptive_names_for_type_parameters +class ComplexClass { + // expect_lint: use_descriptive_names_for_type_parameters + void method() {} +} + +class ValidComplexClass { + void validMethod() {} +} + +// expect_lint: use_descriptive_names_for_type_parameters +typedef SomeAlias = Map>; + +typedef ValidAlias = Map>; + +typedef TwoParamAlias = Map; + +// expect_lint: use_descriptive_names_for_type_parameters +extension Ext on List {} + +extension ValidExt on List {} + +// expect_lint: use_descriptive_names_for_type_parameters +mixin Mixin {} + +mixin ValidMixin {} From 2a0d5ca1c88c140359b6f9bd3ec4d334c9f65d52 Mon Sep 17 00:00:00 2001 From: xJac0b Date: Fri, 6 Jun 2025 15:59:42 +0200 Subject: [PATCH 02/11] refactor code --- ...iptive_names_for_type_parameters_rule.dart | 40 ++++++------- ...ive_names_for_type_parameters_visitor.dart | 60 ------------------- 2 files changed, 17 insertions(+), 83 deletions(-) delete mode 100644 lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart index e9735fe7..b6d67cd5 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -1,7 +1,6 @@ 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/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart'; import 'package:solid_lints/src/models/rule_config.dart'; import 'package:solid_lints/src/models/solid_lint_rule.dart'; @@ -37,48 +36,43 @@ class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { CustomLintContext context, ) { context.registry.addClassDeclaration((node) { - final visitor = UseDescriptiveNamesForTypeParametersVisitor(); - visitor.visitClassDeclaration(node); - _reportViolations(reporter, visitor.singleLetterTypeParameters); + _checkAndReport(node.typeParameters, reporter); }); context.registry.addFunctionDeclaration((node) { - final visitor = UseDescriptiveNamesForTypeParametersVisitor(); - visitor.visitFunctionDeclaration(node); - _reportViolations(reporter, visitor.singleLetterTypeParameters); + _checkAndReport(node.functionExpression.typeParameters, reporter); }); context.registry.addMethodDeclaration((node) { - final visitor = UseDescriptiveNamesForTypeParametersVisitor(); - visitor.visitMethodDeclaration(node); - _reportViolations(reporter, visitor.singleLetterTypeParameters); + _checkAndReport(node.typeParameters, reporter); }); context.registry.addGenericTypeAlias((node) { - final visitor = UseDescriptiveNamesForTypeParametersVisitor(); - visitor.visitGenericTypeAlias(node); - _reportViolations(reporter, visitor.singleLetterTypeParameters); + _checkAndReport(node.typeParameters, reporter); }); context.registry.addExtensionDeclaration((node) { - final visitor = UseDescriptiveNamesForTypeParametersVisitor(); - visitor.visitExtensionDeclaration(node); - _reportViolations(reporter, visitor.singleLetterTypeParameters); + _checkAndReport(node.typeParameters, reporter); }); context.registry.addMixinDeclaration((node) { - final visitor = UseDescriptiveNamesForTypeParametersVisitor(); - visitor.visitMixinDeclaration(node); - _reportViolations(reporter, visitor.singleLetterTypeParameters); + _checkAndReport(node.typeParameters, reporter); }); } - void _reportViolations( + void _checkAndReport( + TypeParameterList? typeParameters, ErrorReporter reporter, - List singleLetterTypeParameters, ) { - for (final param in singleLetterTypeParameters) { - reporter.atNode(param, code); + if (typeParameters == null || typeParameters.typeParameters.length < 3) { + return; + } + + for (final param in typeParameters.typeParameters) { + final name = param.name.lexeme; + if (name.length == 1) { + reporter.atNode(param, code); + } } } } diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart deleted file mode 100644 index f1d2ff5f..00000000 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/ast/visitor.dart'; - -/// AST Visitor which finds type parameters with single-letter names -/// in declarations with three or more type parameters. -class UseDescriptiveNamesForTypeParametersVisitor - extends RecursiveAstVisitor { - /// List of type parameters with single-letter names. - final singleLetterTypeParameters = []; - - @override - void visitClassDeclaration(ClassDeclaration node) { - super.visitClassDeclaration(node); - _checkTypeParameters(node.typeParameters); - } - - @override - void visitFunctionDeclaration(FunctionDeclaration node) { - super.visitFunctionDeclaration(node); - final function = node.functionExpression; - _checkTypeParameters(function.typeParameters); - } - - @override - void visitMethodDeclaration(MethodDeclaration node) { - super.visitMethodDeclaration(node); - _checkTypeParameters(node.typeParameters); - } - - @override - void visitGenericTypeAlias(GenericTypeAlias node) { - super.visitGenericTypeAlias(node); - _checkTypeParameters(node.typeParameters); - } - - @override - void visitExtensionDeclaration(ExtensionDeclaration node) { - super.visitExtensionDeclaration(node); - _checkTypeParameters(node.typeParameters); - } - - @override - void visitMixinDeclaration(MixinDeclaration node) { - super.visitMixinDeclaration(node); - _checkTypeParameters(node.typeParameters); - } - - void _checkTypeParameters(TypeParameterList? typeParameters) { - if (typeParameters == null || typeParameters.typeParameters.length < 3) { - return; - } - - for (final param in typeParameters.typeParameters) { - final name = param.name.lexeme; - if (name.length == 1) { - singleLetterTypeParameters.add(param); - } - } - } -} From cea1860b482712ae18924a6be24f415936a4e383 Mon Sep 17 00:00:00 2001 From: xJac0b Date: Fri, 6 Jun 2025 16:03:25 +0200 Subject: [PATCH 03/11] use cascade notattion --- ...iptive_names_for_type_parameters_rule.dart | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart index b6d67cd5..89f425d4 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -35,29 +35,21 @@ class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { ErrorReporter reporter, CustomLintContext context, ) { - context.registry.addClassDeclaration((node) { - _checkAndReport(node.typeParameters, reporter); - }); - - context.registry.addFunctionDeclaration((node) { - _checkAndReport(node.functionExpression.typeParameters, reporter); - }); - - context.registry.addMethodDeclaration((node) { - _checkAndReport(node.typeParameters, reporter); - }); - - context.registry.addGenericTypeAlias((node) { - _checkAndReport(node.typeParameters, reporter); - }); - - context.registry.addExtensionDeclaration((node) { - _checkAndReport(node.typeParameters, reporter); - }); + void checkTypeParameters(TypeParameterList? typeParameters) { + _checkAndReport(typeParameters, reporter); + } - context.registry.addMixinDeclaration((node) { - _checkAndReport(node.typeParameters, reporter); - }); + context.registry + ..addClassDeclaration((node) => checkTypeParameters(node.typeParameters)) + ..addFunctionDeclaration( + (node) => checkTypeParameters(node.functionExpression.typeParameters), + ) + ..addMethodDeclaration((node) => checkTypeParameters(node.typeParameters)) + ..addGenericTypeAlias((node) => checkTypeParameters(node.typeParameters)) + ..addExtensionDeclaration( + (node) => checkTypeParameters(node.typeParameters), + ) + ..addMixinDeclaration((node) => checkTypeParameters(node.typeParameters)); } void _checkAndReport( From 00b89e75d912c8715af12f7dcae6f7bda6bf51f6 Mon Sep 17 00:00:00 2001 From: xJac0b Date: Sun, 28 Sep 2025 12:17:52 +0200 Subject: [PATCH 04/11] Add test case with nested functions --- ..._descriptive_names_for_type_parameters_test.dart | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart b/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart index 84ad85c3..a462aa13 100644 --- a/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart +++ b/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart @@ -1,5 +1,7 @@ /// Check the `use_descriptive_names_for_type_parameters` rule +// ignore_for_file: unused_element + // expect_lint: use_descriptive_names_for_type_parameters class SomeClass {} @@ -15,6 +17,17 @@ void functionWithTypes(T t, U u, K k) {} void validFunction(Type t, Data d, Context c) {} +void functionWithGenericFunctionDeclarations() { + // expect_lint: use_descriptive_names_for_type_parameters + void _fail3() {} + + void _pass2() {} + + void _pass1() {} + + void _pass0() {} +} + void twoTypeParams(T t, U u) {} // expect_lint: use_descriptive_names_for_type_parameters From 1d8c57d34342ba70e9bb6437f1d0e27901c20fe7 Mon Sep 17 00:00:00 2001 From: xJac0b Date: Sun, 28 Sep 2025 12:20:19 +0200 Subject: [PATCH 05/11] Add parameter for minimum number of type parameters --- ..._names_for_type_parameters_parameters.dart | 22 +++++++++++++++++++ ...iptive_names_for_type_parameters_rule.dart | 14 ++++++++---- .../analysis_options.yaml | 3 ++- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart new file mode 100644 index 00000000..3b8312fa --- /dev/null +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart @@ -0,0 +1,22 @@ +/// A data model class that represents the +/// "use descriptive names for type parameters" input parameters. +class UseDescriptiveNamesForTypeParametersParameters { + static const _defaultMinTypeParameters = 3; + + /// Minimum number of type parameters required before the rule is enforced. + final int minTypeParameters; + + /// Constructor for [UseDescriptiveNamesForTypeParametersParameters] model + const UseDescriptiveNamesForTypeParametersParameters({ + required this.minTypeParameters, + }); + + /// Method for creating from json data + factory UseDescriptiveNamesForTypeParametersParameters.fromJson( + Map json, + ) => + UseDescriptiveNamesForTypeParametersParameters( + minTypeParameters: + json['min_type_parameters'] as int? ?? _defaultMinTypeParameters, + ); +} diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart index 89f425d4..ea13be9d 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -1,13 +1,15 @@ 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/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart'; import 'package:solid_lints/src/models/rule_config.dart'; import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// A `use_descriptive_names_for_type_parameters` rule which /// warns about single-letter type parameter names when there are /// three or more type parameters. -class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { +class UseDescriptiveNamesForTypeParametersRule + extends SolidLintRule { /// The lint rule name. static const lintName = 'use_descriptive_names_for_type_parameters'; @@ -21,9 +23,11 @@ class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { final rule = RuleConfig( configs: configs, name: lintName, - problemMessage: (_) => + paramsParser: UseDescriptiveNamesForTypeParametersParameters.fromJson, + problemMessage: (value) => 'Type parameters should have descriptive names instead ' - 'of single letters when there are three or more type parameters.', + 'of single letters when there are ${value.minTypeParameters} or ' + 'more type parameters.', ); return UseDescriptiveNamesForTypeParametersRule._(rule); @@ -56,7 +60,9 @@ class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { TypeParameterList? typeParameters, ErrorReporter reporter, ) { - if (typeParameters == null || typeParameters.typeParameters.length < 3) { + if (typeParameters == null || + typeParameters.typeParameters.length < + config.parameters.minTypeParameters) { return; } diff --git a/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml b/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml index 852d28aa..dfcddd4f 100644 --- a/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml +++ b/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml @@ -1,3 +1,4 @@ custom_lint: rules: - - use_descriptive_names_for_type_parameters + - use_descriptive_names_for_type_parameters: + min_type_parameters: 3 From cac35b6813a990b0d5734cdd3f550462c6760554 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Tue, 7 Jul 2026 15:32:23 +0300 Subject: [PATCH 06/11] docs: add missing period to fromJson documentation comment --- .../use_descriptive_names_for_type_parameters_parameters.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart index 3b8312fa..ec9fb13a 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart @@ -11,7 +11,7 @@ class UseDescriptiveNamesForTypeParametersParameters { required this.minTypeParameters, }); - /// Method for creating from json data + /// Method for creating from json data. factory UseDescriptiveNamesForTypeParametersParameters.fromJson( Map json, ) => From feadc70121cd4da19b5d9eeb668d523f3e8a2238 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Tue, 7 Jul 2026 16:55:22 +0300 Subject: [PATCH 07/11] refactor: migrate use_descriptive_names_for_type_parameters rule --- lib/analysis_options.yaml | 1 + lib/main.dart | 4 + ..._names_for_type_parameters_parameters.dart | 16 +- ...iptive_names_for_type_parameters_rule.dart | 122 ++++++------ ...ive_names_for_type_parameters_visitor.dart | 81 ++++++++ ...e_names_for_type_parameters_rule_test.dart | 177 ++++++++++++++++++ 6 files changed, 341 insertions(+), 60 deletions(-) create mode 100644 lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart create mode 100644 test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart diff --git a/lib/analysis_options.yaml b/lib/analysis_options.yaml index dd2a9c95..9dbf6bad 100644 --- a/lib/analysis_options.yaml +++ b/lib/analysis_options.yaml @@ -103,6 +103,7 @@ solid_lints: proper_super_calls: true named_parameters_ordering: true use_nearest_context: true + use_descriptive_names_for_type_parameters: true linter: rules: diff --git a/lib/main.dart b/lib/main.dart index 43c08108..6910da4c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -33,6 +33,7 @@ import 'package:solid_lints/src/lints/prefer_first/prefer_first_rule.dart'; import 'package:solid_lints/src/lints/prefer_last/fixes/prefer_last_fix.dart'; import 'package:solid_lints/src/lints/prefer_last/prefer_last_rule.dart'; import 'package:solid_lints/src/lints/proper_super_calls/proper_super_calls_rule.dart'; +import 'package:solid_lints/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart'; import 'package:solid_lints/src/lints/use_nearest_context/fixes/rename_nearest_context_parameter_fix.dart'; import 'package:solid_lints/src/lints/use_nearest_context/use_nearest_context_rule.dart'; @@ -80,6 +81,9 @@ class SolidLintsPlugin extends Plugin { CyclomaticComplexityRule(analysisOptionsLoader: analysisLoader), NoEmptyBlockRule(analysisOptionsLoader: analysisLoader), UseNearestContextRule(), + UseDescriptiveNamesForTypeParametersRule( + analysisOptionsLoader: analysisLoader, + ), NoMagicNumberRule(analysisOptionsLoader: analysisLoader), preferFirstRule, preferConditionalExpressionsRule, diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart index ec9fb13a..fbb86b87 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart @@ -11,12 +11,18 @@ class UseDescriptiveNamesForTypeParametersParameters { required this.minTypeParameters, }); + /// Empty [UseDescriptiveNamesForTypeParametersParameters] model. + factory UseDescriptiveNamesForTypeParametersParameters.empty() { + return const UseDescriptiveNamesForTypeParametersParameters( + minTypeParameters: _defaultMinTypeParameters, + ); + } + /// Method for creating from json data. factory UseDescriptiveNamesForTypeParametersParameters.fromJson( Map json, - ) => - UseDescriptiveNamesForTypeParametersParameters( - minTypeParameters: - json['min_type_parameters'] as int? ?? _defaultMinTypeParameters, - ); + ) => UseDescriptiveNamesForTypeParametersParameters( + minTypeParameters: + json['min_type_parameters'] as int? ?? _defaultMinTypeParameters, + ); } diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart index ea13be9d..859a0167 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -1,76 +1,88 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/error/listener.dart'; -import 'package:custom_lint_builder/custom_lint_builder.dart'; +import 'package:analyzer/analysis_rule/rule_context.dart'; +import 'package:analyzer/analysis_rule/rule_visitor_registry.dart'; +import 'package:analyzer/error/error.dart'; import 'package:solid_lints/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart'; -import 'package:solid_lints/src/models/rule_config.dart'; +import 'package:solid_lints/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart'; import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// A `use_descriptive_names_for_type_parameters` rule which /// warns about single-letter type parameter names when there are /// three or more type parameters. +/// +/// ### Example: +/// +/// Assuming config: +/// +/// ```yaml +/// plugins: +/// solid_lints: +/// diagnostics: +/// use_descriptive_names_for_type_parameters: +/// min_type_parameters: 3 +/// ``` +/// +/// #### BAD: +/// ```dart +/// class MyClass {} // LINT +/// ``` +/// +/// #### GOOD: +/// ```dart +/// class MyClass {} // OK +/// class MyClass2 {} // OK +/// ``` class UseDescriptiveNamesForTypeParametersRule extends SolidLintRule { /// The lint rule name. static const lintName = 'use_descriptive_names_for_type_parameters'; - UseDescriptiveNamesForTypeParametersRule._(super.config); + static const _code = LintCode( + lintName, + 'Type parameters should have descriptive names instead ' + 'of single letters when there are {0} or ' + 'more type parameters.', + ); - /// Creates a new instance of [UseDescriptiveNamesForTypeParametersRule] - /// based on the lint configuration. - factory UseDescriptiveNamesForTypeParametersRule.createRule( - CustomLintConfigs configs, - ) { - final rule = RuleConfig( - configs: configs, - name: lintName, - paramsParser: UseDescriptiveNamesForTypeParametersParameters.fromJson, - problemMessage: (value) => - 'Type parameters should have descriptive names instead ' - 'of single letters when there are ${value.minTypeParameters} or ' - 'more type parameters.', - ); + @override + DiagnosticCode get diagnosticCode => _code; - return UseDescriptiveNamesForTypeParametersRule._(rule); - } + /// Creates a new instance of [UseDescriptiveNamesForTypeParametersRule]. + UseDescriptiveNamesForTypeParametersRule({ + required super.analysisOptionsLoader, + }) : super.withParameters( + name: lintName, + description: + 'Warns about single-letter type parameter names when there are ' + 'three or more type parameters.', + parametersParser: + UseDescriptiveNamesForTypeParametersParameters.fromJson, + ); @override - void run( - CustomLintResolver resolver, - ErrorReporter reporter, - CustomLintContext context, + void registerNodeProcessors( + RuleVisitorRegistry registry, + RuleContext context, ) { - void checkTypeParameters(TypeParameterList? typeParameters) { - _checkAndReport(typeParameters, reporter); - } + super.registerNodeProcessors(registry, context); - context.registry - ..addClassDeclaration((node) => checkTypeParameters(node.typeParameters)) - ..addFunctionDeclaration( - (node) => checkTypeParameters(node.functionExpression.typeParameters), - ) - ..addMethodDeclaration((node) => checkTypeParameters(node.typeParameters)) - ..addGenericTypeAlias((node) => checkTypeParameters(node.typeParameters)) - ..addExtensionDeclaration( - (node) => checkTypeParameters(node.typeParameters), - ) - ..addMixinDeclaration((node) => checkTypeParameters(node.typeParameters)); - } + final parameters = + getParametersForContext(context) ?? + UseDescriptiveNamesForTypeParametersParameters.empty(); - void _checkAndReport( - TypeParameterList? typeParameters, - ErrorReporter reporter, - ) { - if (typeParameters == null || - typeParameters.typeParameters.length < - config.parameters.minTypeParameters) { - return; - } + final visitor = UseDescriptiveNamesForTypeParametersVisitor( + this, + parameters, + ); - for (final param in typeParameters.typeParameters) { - final name = param.name.lexeme; - if (name.length == 1) { - reporter.atNode(param, code); - } - } + registry.addClassDeclaration(this, visitor); + registry.addEnumDeclaration(this, visitor); + registry.addFunctionExpression(this, visitor); + registry.addMethodDeclaration(this, visitor); + registry.addGenericTypeAlias(this, visitor); + registry.addFunctionTypeAlias(this, visitor); + registry.addGenericFunctionType(this, visitor); + registry.addExtensionDeclaration(this, visitor); + registry.addMixinDeclaration(this, visitor); + registry.addExtensionTypeDeclaration(this, visitor); } } diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart new file mode 100644 index 00000000..287821ab --- /dev/null +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart @@ -0,0 +1,81 @@ +import 'package:analyzer/dart/ast/ast.dart'; +import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:solid_lints/src/lints/use_descriptive_names_for_type_parameters/models/use_descriptive_names_for_type_parameters_parameters.dart'; +import 'package:solid_lints/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart'; + +/// A visitor that checks descriptive names for type parameters on declarations. +class UseDescriptiveNamesForTypeParametersVisitor + extends SimpleAstVisitor { + final UseDescriptiveNamesForTypeParametersRule _rule; + final UseDescriptiveNamesForTypeParametersParameters _parameters; + + /// Creates a new instance of [UseDescriptiveNamesForTypeParametersVisitor]. + UseDescriptiveNamesForTypeParametersVisitor(this._rule, this._parameters); + + void _checkAndReport(TypeParameterList? typeParameters) { + if (typeParameters == null || + typeParameters.typeParameters.length < _parameters.minTypeParameters) { + return; + } + + for (final param in typeParameters.typeParameters) { + final name = param.name.lexeme; + if (name.length == 1 && name != '_') { + _rule.reportAtNode( + param, + arguments: [_parameters.minTypeParameters.toString()], + ); + } + } + } + + @override + void visitClassDeclaration(ClassDeclaration node) { + _checkAndReport(node.namePart.typeParameters); + } + + @override + void visitEnumDeclaration(EnumDeclaration node) { + _checkAndReport(node.namePart.typeParameters); + } + + @override + void visitFunctionExpression(FunctionExpression node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitMethodDeclaration(MethodDeclaration node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitGenericTypeAlias(GenericTypeAlias node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitFunctionTypeAlias(FunctionTypeAlias node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitGenericFunctionType(GenericFunctionType node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitExtensionDeclaration(ExtensionDeclaration node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitMixinDeclaration(MixinDeclaration node) { + _checkAndReport(node.typeParameters); + } + + @override + void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) { + _checkAndReport(node.primaryConstructor.typeParameters); + } +} diff --git a/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart b/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart new file mode 100644 index 00000000..2f816d29 --- /dev/null +++ b/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart @@ -0,0 +1,177 @@ +import 'package:analyzer_testing/analysis_rule/analysis_rule.dart'; +import 'package:analyzer_testing/utilities/utilities.dart'; +import 'package:solid_lints/src/common/parameter_parser/analysis_options_loader.dart'; +import 'package:solid_lints/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../../../lints/auto_test_lint_offsets.dart'; + +void main() { + defineReflectiveSuite(() { + defineReflectiveTests(UseDescriptiveNamesForTypeParametersRuleTest); + }); +} + +@reflectiveTest +class UseDescriptiveNamesForTypeParametersRuleTest extends AnalysisRuleTest + with AutoTestLintOffsets { + static const _mockAnalysisOptionsContent = ''' +plugins: + solid_lints: + diagnostics: + use_descriptive_names_for_type_parameters: + min_type_parameters: 3 + '''; + + @override + void setUp() { + rule = UseDescriptiveNamesForTypeParametersRule( + analysisOptionsLoader: AnalysisOptionsLoader( + resourceProvider: resourceProvider, + ), + ); + super.setUp(); + + newAnalysisOptionsYamlFile( + testPackageRootPath, + '''${analysisOptionsContent(rules: [rule.name])} +$_mockAnalysisOptionsContent''', + ); + } + + Future test_reports_on_class() async { + await assertAutoDiagnostics(''' +class MyClass< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +> {} +'''); + } + + Future test_reports_on_enum() async { + await assertAutoDiagnostics(''' +enum MyEnum< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +> { + a, b +} +'''); + } + + Future test_reports_on_method() async { + await assertAutoDiagnostics(''' +class MyClass { + void myMethod< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} + >() {} +} +'''); + } + + Future test_reports_on_function() async { + await assertAutoDiagnostics(''' +void myFunction< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +>() {} +'''); + } + + Future test_reports_on_mixin() async { + await assertAutoDiagnostics(''' +mixin MyMixin< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +> {} +'''); + } + + Future test_reports_on_extension() async { + await assertAutoDiagnostics(''' +extension MyExtension< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +> on List {} +'''); + } + + Future test_reports_on_generic_type_alias() async { + await assertAutoDiagnostics(''' +typedef MyAlias< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +> = Map; +'''); + } + + Future test_reports_on_function_type_alias() async { + await assertAutoDiagnostics(''' +typedef void MyFuncAlias< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +>(T a, U b, V c); +'''); + } + + Future test_reports_on_generic_function_type() async { + await assertAutoDiagnostics(''' +void test() { + final void Function< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} + >(T, U, V) func; +} +'''); + } + + Future test_reports_on_anonymous_function() async { + await assertAutoDiagnostics(''' +void test() { + final func = < + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} + >(T a, U b, V c) => a; +} +'''); + } + + Future test_reports_on_extension_type() async { + await assertAutoDiagnostics(''' +extension type MyExtensionType< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +>(List list) {} +'''); + } + + Future test_does_not_report_on_descriptive_names() async { + await assertNoDiagnostics(''' +class MyClass {} +'''); + } + + Future test_does_not_report_on_wildcard() async { + await assertNoDiagnostics(''' +class MyClass {} +'''); + } + + Future test_does_not_report_below_threshold() async { + await assertNoDiagnostics(''' +class MyClass {} +'''); + } +} From 4c11e628d85233801660823f621cf541d5d6b572 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Wed, 15 Jul 2026 11:12:41 +0300 Subject: [PATCH 08/11] feat: extend use_descriptive_names_for_type_parameters to check class type aliases and include configuration for min_type_parameters --- ...iptive_names_for_type_parameters_rule.dart | 1 + ...ive_names_for_type_parameters_visitor.dart | 5 ++++ ...e_names_for_type_parameters_rule_test.dart | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart index 859a0167..f9929c49 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -75,6 +75,7 @@ class UseDescriptiveNamesForTypeParametersRule ); registry.addClassDeclaration(this, visitor); + registry.addClassTypeAlias(this, visitor); registry.addEnumDeclaration(this, visitor); registry.addFunctionExpression(this, visitor); registry.addMethodDeclaration(this, visitor); diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart index 287821ab..0877132b 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart @@ -34,6 +34,11 @@ class UseDescriptiveNamesForTypeParametersVisitor _checkAndReport(node.namePart.typeParameters); } + @override + void visitClassTypeAlias(ClassTypeAlias node) { + _checkAndReport(node.typeParameters); + } + @override void visitEnumDeclaration(EnumDeclaration node) { _checkAndReport(node.namePart.typeParameters); diff --git a/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart b/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart index 2f816d29..2b27ba46 100644 --- a/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart +++ b/test/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule_test.dart @@ -49,6 +49,18 @@ class MyClass< '''); } + Future test_reports_on_class_type_alias() async { + await assertAutoDiagnostics(''' +class Base {} +mixin MyMixin {} +class MyAlias< + ${expectLint('T')}, + ${expectLint('U')}, + ${expectLint('V')} +> = Base with MyMixin; +'''); + } + Future test_reports_on_enum() async { await assertAutoDiagnostics(''' enum MyEnum< @@ -172,6 +184,22 @@ class MyClass {} Future test_does_not_report_below_threshold() async { await assertNoDiagnostics(''' class MyClass {} +'''); + } + + Future test_reports_when_min_type_parameters_is_1() async { + newAnalysisOptionsYamlFile( + testPackageRootPath, + '''${analysisOptionsContent(rules: [rule.name])} +plugins: + solid_lints: + diagnostics: + use_descriptive_names_for_type_parameters: + min_type_parameters: 1''', + ); + + await assertAutoDiagnostics(''' +class MyClass<${expectLint('T')}> {} '''); } } From 671fdc792d0d8ea94d2f87f793006df65b764283 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Wed, 15 Jul 2026 11:15:14 +0300 Subject: [PATCH 09/11] feat: add use_descriptive_names_for_type_parameters rule and bump version to 1.0.0 --- CHANGELOG.md | 45 ++++++++++++++++++++++++++++----------------- pubspec.yaml | 2 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c8c46d4..f4ccc394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,10 @@ ## 1.0.0 - feat!: migrate to analyzer_server_plugin -- refactor: replace `avoid_unnecessary_type_casts` rule with dart analyzer's `unnecessary_cast` +- refactor: replace `avoid_unnecessary_type_casts` rule with dart analyzer's + `unnecessary_cast` - Added `use_nearest_context` rule. +- Added `use_descriptive_names_for_type_parameters` rule. ## 0.3.3 @@ -17,9 +19,9 @@ - Added `allow_with_comments` parameter for `no_empty_block` lint. - Added extension support for `avoid_using_api` -- Added `exclude_entity` parameter for `prefer_match_file_name` lint. - It is now possible to configure this lint to ignore `enum`, - `extension` and `mixin` declarations via `analysis_options.yaml`. +- Added `exclude_entity` parameter for `prefer_match_file_name` lint. It is now + possible to configure this lint to ignore `enum`, `extension` and `mixin` + declarations via `analysis_options.yaml`. ## 0.3.0 @@ -30,7 +32,8 @@ - `function_lines_of_code` - `no_empty_bloc` - `number_of_parameters` -- BREAKING CHANGE: Renamed `excludeNames` parameter to `exclude` for `function_lines_of_code` lint. +- BREAKING CHANGE: Renamed `excludeNames` parameter to `exclude` for + `function_lines_of_code` lint. - Fixed an issue with `prefer_early_retrun` for throw expression - `number_of_parameters` lint: added `copyWith` to the default exclude list. - Update dependencies: @@ -53,28 +56,36 @@ ## 0.2.0 - Added `avoid_final_with_getter` rule -- 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 () +- 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. +- 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 ## 0.1.5 - Added `avoid_debug_print` rule - Fixed an issue with no_magic_number lint -- Fixed `avoid_unused_parameters` to report positional parameters from typedef if their name are not underscores. +- Fixed `avoid_unused_parameters` to report positional parameters from typedef + if their name are not underscores. - Improvement for `avoid_returning_widget` lint: - ignores methods that override ones that return widget (build() for example) - no longer allows returning widgets from methods/functions named build - 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 () - Credits: Arthur Miranda () +- Set default `cyclomatic_complexity` to 10 + () Credits: Arthur + Miranda () ## 0.1.4 @@ -108,8 +119,7 @@ - avoid_unnecessary_type_casts - avoid_unrelated_type_assertions - avoid_unused_parameters - - avoid_using_api - Credits: getBoolean () + - avoid_using_api Credits: getBoolean () - cyclomatic_complexity - double_literal_format - function_lines_of_code @@ -176,7 +186,8 @@ ## 0.0.13 -- enable use_colored_box & use_decorated_box + add more comments about specific lints +- enable use_colored_box & use_decorated_box + add more comments about specific + lints ## 0.0.12 diff --git a/pubspec.yaml b/pubspec.yaml index 56c55842..cd4a0f5a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: solid_lints description: Lints for Dart and Flutter based on software industry standards and best practices. -version: 0.3.4 +version: 1.0.0 homepage: https://github.com/solid-software/solid_lints/ documentation: https://solid-software.github.io/solid_lints/docs/intro topics: [lints, linter, lint, analysis, analyzer] From 3d1f02217a6202a7e09c0c471d062aed36fc36a1 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Wed, 15 Jul 2026 11:20:01 +0300 Subject: [PATCH 10/11] chore: remove use_descriptive_names_for_type_parameters test files --- .../analysis_options.yaml | 4 -- ...iptive_names_for_type_parameters_test.dart | 58 ------------------- 2 files changed, 62 deletions(-) delete mode 100644 lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml delete mode 100644 lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart diff --git a/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml b/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml deleted file mode 100644 index dfcddd4f..00000000 --- a/lint_test/use_descriptive_names_for_type_parameters_test/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -custom_lint: - rules: - - use_descriptive_names_for_type_parameters: - min_type_parameters: 3 diff --git a/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart b/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart deleted file mode 100644 index a462aa13..00000000 --- a/lint_test/use_descriptive_names_for_type_parameters_test/use_descriptive_names_for_type_parameters_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -/// Check the `use_descriptive_names_for_type_parameters` rule - -// ignore_for_file: unused_element - -// expect_lint: use_descriptive_names_for_type_parameters -class SomeClass {} - -class ValidClass {} - -class TwoParams {} - -// expect_lint: use_descriptive_names_for_type_parameters -class AnotherClass {} - -// expect_lint: use_descriptive_names_for_type_parameters -void functionWithTypes(T t, U u, K k) {} - -void validFunction(Type t, Data d, Context c) {} - -void functionWithGenericFunctionDeclarations() { - // expect_lint: use_descriptive_names_for_type_parameters - void _fail3() {} - - void _pass2() {} - - void _pass1() {} - - void _pass0() {} -} - -void twoTypeParams(T t, U u) {} - -// expect_lint: use_descriptive_names_for_type_parameters -class ComplexClass { - // expect_lint: use_descriptive_names_for_type_parameters - void method() {} -} - -class ValidComplexClass { - void validMethod() {} -} - -// expect_lint: use_descriptive_names_for_type_parameters -typedef SomeAlias = Map>; - -typedef ValidAlias = Map>; - -typedef TwoParamAlias = Map; - -// expect_lint: use_descriptive_names_for_type_parameters -extension Ext on List {} - -extension ValidExt on List {} - -// expect_lint: use_descriptive_names_for_type_parameters -mixin Mixin {} - -mixin ValidMixin {} From 7bb385678b7c85f310e3b052753e893043c4ee63 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 17 Jul 2026 16:42:43 +0300 Subject: [PATCH 11/11] refactor: simplify visitor implementation using pattern matching and cascade notation for registry registration --- ...iptive_names_for_type_parameters_rule.dart | 23 +++--- ...ive_names_for_type_parameters_visitor.dart | 81 ++++++++----------- 2 files changed, 46 insertions(+), 58 deletions(-) diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart index f9929c49..a994b2b8 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/use_descriptive_names_for_type_parameters_rule.dart @@ -74,16 +74,17 @@ class UseDescriptiveNamesForTypeParametersRule parameters, ); - registry.addClassDeclaration(this, visitor); - registry.addClassTypeAlias(this, visitor); - registry.addEnumDeclaration(this, visitor); - registry.addFunctionExpression(this, visitor); - registry.addMethodDeclaration(this, visitor); - registry.addGenericTypeAlias(this, visitor); - registry.addFunctionTypeAlias(this, visitor); - registry.addGenericFunctionType(this, visitor); - registry.addExtensionDeclaration(this, visitor); - registry.addMixinDeclaration(this, visitor); - registry.addExtensionTypeDeclaration(this, visitor); + registry + ..addClassDeclaration(this, visitor) + ..addClassTypeAlias(this, visitor) + ..addEnumDeclaration(this, visitor) + ..addFunctionExpression(this, visitor) + ..addMethodDeclaration(this, visitor) + ..addGenericTypeAlias(this, visitor) + ..addFunctionTypeAlias(this, visitor) + ..addGenericFunctionType(this, visitor) + ..addExtensionDeclaration(this, visitor) + ..addMixinDeclaration(this, visitor) + ..addExtensionTypeDeclaration(this, visitor); } } diff --git a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart index 0877132b..428c6f1b 100644 --- a/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart +++ b/lib/src/lints/use_descriptive_names_for_type_parameters/visitors/use_descriptive_names_for_type_parameters_visitor.dart @@ -9,78 +9,65 @@ class UseDescriptiveNamesForTypeParametersVisitor final UseDescriptiveNamesForTypeParametersRule _rule; final UseDescriptiveNamesForTypeParametersParameters _parameters; + int get _minParameters => _parameters.minTypeParameters; + /// Creates a new instance of [UseDescriptiveNamesForTypeParametersVisitor]. UseDescriptiveNamesForTypeParametersVisitor(this._rule, this._parameters); - void _checkAndReport(TypeParameterList? typeParameters) { - if (typeParameters == null || - typeParameters.typeParameters.length < _parameters.minTypeParameters) { - return; - } - - for (final param in typeParameters.typeParameters) { - final name = param.name.lexeme; - if (name.length == 1 && name != '_') { - _rule.reportAtNode( - param, - arguments: [_parameters.minTypeParameters.toString()], - ); - } + void _visit(TypeParameterList? types) { + if (types case TypeParameterList( + typeParameters: final ps, + ) when ps.length >= _minParameters) { + ps.where(_hasInvalidShortName).forEach(_report); } } + bool _hasInvalidShortName(TypeParameter p) => + p.name.length == 1 && p.name.lexeme != '_'; + + void _report(TypeParameter p) => + _rule.reportAtNode(p, arguments: ['$_minParameters']); + @override - void visitClassDeclaration(ClassDeclaration node) { - _checkAndReport(node.namePart.typeParameters); - } + void visitClassDeclaration(ClassDeclaration node) => + _visit(node.namePart.typeParameters); @override - void visitClassTypeAlias(ClassTypeAlias node) { - _checkAndReport(node.typeParameters); - } + void visitClassTypeAlias(ClassTypeAlias node) => _visit(node.typeParameters); @override - void visitEnumDeclaration(EnumDeclaration node) { - _checkAndReport(node.namePart.typeParameters); - } + void visitEnumDeclaration(EnumDeclaration node) => + _visit(node.namePart.typeParameters); @override - void visitFunctionExpression(FunctionExpression node) { - _checkAndReport(node.typeParameters); - } + void visitFunctionExpression(FunctionExpression node) => + _visit(node.typeParameters); @override - void visitMethodDeclaration(MethodDeclaration node) { - _checkAndReport(node.typeParameters); - } + void visitMethodDeclaration(MethodDeclaration node) => + _visit(node.typeParameters); @override - void visitGenericTypeAlias(GenericTypeAlias node) { - _checkAndReport(node.typeParameters); - } + void visitGenericTypeAlias(GenericTypeAlias node) => + _visit(node.typeParameters); @override - void visitFunctionTypeAlias(FunctionTypeAlias node) { - _checkAndReport(node.typeParameters); - } + void visitFunctionTypeAlias(FunctionTypeAlias node) => + _visit(node.typeParameters); @override - void visitGenericFunctionType(GenericFunctionType node) { - _checkAndReport(node.typeParameters); - } + void visitGenericFunctionType(GenericFunctionType node) => + _visit(node.typeParameters); @override - void visitExtensionDeclaration(ExtensionDeclaration node) { - _checkAndReport(node.typeParameters); - } + void visitExtensionDeclaration(ExtensionDeclaration node) => + _visit(node.typeParameters); @override - void visitMixinDeclaration(MixinDeclaration node) { - _checkAndReport(node.typeParameters); - } + void visitMixinDeclaration(MixinDeclaration node) => + _visit(node.typeParameters); @override - void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) { - _checkAndReport(node.primaryConstructor.typeParameters); - } + void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) => + _visit(node.primaryConstructor.typeParameters); }