From 95bd88e941108a43c768466511a4f2222aa4371e Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 13:30:27 +0300 Subject: [PATCH 1/7] feat: add exclude_annotation support to avoid_unused_parameters lint to ignore generated classes --- lib/analysis_options.yaml | 5 ++- .../excluded_annotations_list_parameter.dart | 45 +++++++++++++++++++ .../avoid_unused_parameters_rule.dart | 7 +++ .../avoid_unused_parameters_parameters.dart | 9 ++++ .../avoid_unused_parameters_visitor.dart | 5 +++ .../avoid_unused_parameters_rule_test.dart | 33 ++++++++++++++ 6 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 lib/src/common/parameters/excluded_annotations_list_parameter.dart diff --git a/lib/analysis_options.yaml b/lib/analysis_options.yaml index 21857abc..bfc02b97 100644 --- a/lib/analysis_options.yaml +++ b/lib/analysis_options.yaml @@ -50,7 +50,10 @@ custom_lint: - avoid_unnecessary_setstate - avoid_unnecessary_type_assertions - avoid_unrelated_type_assertions - - avoid_unused_parameters + - avoid_unused_parameters: + exclude_annotation: + - freezed + - unfreezed - avoid_debug_print_in_release - avoid_final_with_getter diff --git a/lib/src/common/parameters/excluded_annotations_list_parameter.dart b/lib/src/common/parameters/excluded_annotations_list_parameter.dart new file mode 100644 index 00000000..29e38e86 --- /dev/null +++ b/lib/src/common/parameters/excluded_annotations_list_parameter.dart @@ -0,0 +1,45 @@ +import 'package:analyzer/dart/ast/ast.dart'; + +/// A parameter model representing excluded annotations for linting. +/// It defines class-level annotations that indicate when class members +/// should be ignored during analysis. +class ExcludedAnnotationsListParameter { + /// The set of excluded annotation names. + final Set excludedAnnotations; + + /// A common parameter key for analysis_options.yaml + static const String excludeAnnotationKey = 'exclude_annotation'; + + /// Constructor for [ExcludedAnnotationsListParameter] class + ExcludedAnnotationsListParameter({ + required this.excludedAnnotations, + }); + + /// Method for creating from json data + factory ExcludedAnnotationsListParameter.fromJson(Map json) { + final raw = json[excludeAnnotationKey]; + if (raw is List) { + return ExcludedAnnotationsListParameter( + excludedAnnotations: Set.from(raw.whereType()), + ); + } + + return ExcludedAnnotationsListParameter( + excludedAnnotations: {}, + ); + } + + /// Returns whether the target node should be ignored during analysis because + /// its enclosing class is annotated with one of the excluded annotations. + bool shouldIgnore(Declaration node) { + if (excludedAnnotations.isEmpty) return false; + + final classDecl = node.thisOrAncestorOfType(); + if (classDecl == null) return false; + + return classDecl.metadata.any((annotation) { + final name = annotation.name.name; + return excludedAnnotations.contains(name); + }); + } +} 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 ab9d7e9c..a1858429 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 @@ -11,6 +11,13 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// Parameters whose names consist only of underscores are also ignored. /// Overridden methods and methods used as tear-offs are skipped. /// +/// ### Parameters +/// +/// #### exclude_annotation +/// A list of class annotations (such as `freezed` or `unfreezed`) whose +/// constructor parameters should be ignored by this rule (useful for code +/// generation). +/// /// {@template solid_lints.avoid_unused_parameters.example} /// ### Example /// diff --git a/lib/src/lints/avoid_unused_parameters/models/avoid_unused_parameters_parameters.dart b/lib/src/lints/avoid_unused_parameters/models/avoid_unused_parameters_parameters.dart index a6a20cbd..67e5d326 100644 --- a/lib/src/lints/avoid_unused_parameters/models/avoid_unused_parameters_parameters.dart +++ b/lib/src/lints/avoid_unused_parameters/models/avoid_unused_parameters_parameters.dart @@ -1,3 +1,4 @@ +import 'package:solid_lints/src/common/parameters/excluded_annotations_list_parameter.dart'; import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart'; /// A data model class that represents the `avoid_unused_parameters` input @@ -6,15 +7,22 @@ class AvoidUnusedParametersParameters { /// A list of methods that should be excluded from the lint. final ExcludedIdentifiersListParameter exclude; + /// A list of annotations that should be ignored during class check. + final ExcludedAnnotationsListParameter excludeAnnotation; + /// Constructor for [AvoidUnusedParametersParameters] model. AvoidUnusedParametersParameters({ required this.exclude, + required this.excludeAnnotation, }); /// Empty [AvoidUnusedParametersParameters] model, excludes nothing. factory AvoidUnusedParametersParameters.empty() { return AvoidUnusedParametersParameters( exclude: ExcludedIdentifiersListParameter(exclude: []), + excludeAnnotation: ExcludedAnnotationsListParameter( + excludedAnnotations: {}, + ), ); } @@ -22,6 +30,7 @@ class AvoidUnusedParametersParameters { factory AvoidUnusedParametersParameters.fromJson(Map json) { return AvoidUnusedParametersParameters( exclude: ExcludedIdentifiersListParameter.defaultFromJson(json), + excludeAnnotation: ExcludedAnnotationsListParameter.fromJson(json), ); } } 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 e10fb310..3dac3e66 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 @@ -47,6 +47,8 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { if (parent is ClassDeclaration && parent.abstractKeyword != null || node.externalKeyword != null || + node.redirectedConstructor != null || + _hasExcludedAnnotationClass(node) || parameters.parameters.isEmpty) { return; } @@ -113,6 +115,9 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { bool _isExcluded(Declaration node) => _parameters.exclude.shouldIgnore(node); + bool _hasExcludedAnnotationClass(ConstructorDeclaration node) => + _parameters.excludeAnnotation.shouldIgnore(node); + Iterable _filterOutUnderscoresAndNamed( AstNode body, Iterable parameters, diff --git a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart index 440ee2e4..db9bcef7 100644 --- a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart +++ b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart @@ -50,6 +50,7 @@ class Placeholder extends StatelessWidget { 'SimpleClassName', 'exclude', ], + 'exclude_annotation': ['freezed'], }, ); @@ -381,4 +382,36 @@ class SimpleClassName { [lint(38, 8), lint(118, 8)], ); } + + Future + test_does_not_report_on_redirecting_factory_constructors() async { + await assertNoDiagnostics(r''' +class RedirectingClass { + const factory RedirectingClass({required int parameter}) = _RedirectingClass; +} + +class _RedirectingClass implements RedirectingClass { + final int parameter; + const _RedirectingClass({required this.parameter}); +} +'''); + } + + Future test_does_not_report_on_freezed_classes() async { + await assertNoDiagnostics(r''' +const freezed = Object(); + +@freezed +class Test { + const factory Test({ + bool test, + }) = _Test; +} + +class _Test implements Test { + final bool? test; + const _Test({this.test}); +} +'''); + } } From aaf7c99c7dd01bb125ad059676c4fa93d382f0bc Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 14:30:19 +0300 Subject: [PATCH 2/7] feat: allow configuration parameters to accept single strings in addition to lists and add associated parsing tests --- .../excluded_annotations_list_parameter.dart | 4 + .../excluded_entities_list_parameter.dart | 6 +- .../excluded_identifiers_list_parameter.dart | 14 +++- .../avoid_unused_parameters_rule_test.dart | 34 ++++++++ .../parameters/parameters_parsing_test.dart | 78 +++++++++++++++++++ 5 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 test/src/common/parameters/parameters_parsing_test.dart diff --git a/lib/src/common/parameters/excluded_annotations_list_parameter.dart b/lib/src/common/parameters/excluded_annotations_list_parameter.dart index 29e38e86..96faed08 100644 --- a/lib/src/common/parameters/excluded_annotations_list_parameter.dart +++ b/lib/src/common/parameters/excluded_annotations_list_parameter.dart @@ -22,6 +22,10 @@ class ExcludedAnnotationsListParameter { return ExcludedAnnotationsListParameter( excludedAnnotations: Set.from(raw.whereType()), ); + } else if (raw is String) { + return ExcludedAnnotationsListParameter( + excludedAnnotations: {raw}, + ); } return ExcludedAnnotationsListParameter( diff --git a/lib/src/common/parameters/excluded_entities_list_parameter.dart b/lib/src/common/parameters/excluded_entities_list_parameter.dart index 34d4277c..80e81bc9 100644 --- a/lib/src/common/parameters/excluded_entities_list_parameter.dart +++ b/lib/src/common/parameters/excluded_entities_list_parameter.dart @@ -24,7 +24,11 @@ class ExcludedEntitiesListParameter { final raw = json['exclude_entity']; if (raw is List) { return ExcludedEntitiesListParameter( - excludedEntityNames: Set.from(raw), + excludedEntityNames: Set.from(raw.whereType()), + ); + } else if (raw is String) { + return ExcludedEntitiesListParameter( + excludedEntityNames: {raw}, ); } diff --git a/lib/src/common/parameters/excluded_identifiers_list_parameter.dart b/lib/src/common/parameters/excluded_identifiers_list_parameter.dart index 526201a4..0b769b61 100644 --- a/lib/src/common/parameters/excluded_identifiers_list_parameter.dart +++ b/lib/src/common/parameters/excluded_identifiers_list_parameter.dart @@ -43,10 +43,16 @@ class ExcludedIdentifiersListParameter { factory ExcludedIdentifiersListParameter.defaultFromJson( Map json, ) { - final excludeList = - json[ExcludedIdentifiersListParameter.excludeParameterName] - as Iterable? ?? - []; + final raw = json[ExcludedIdentifiersListParameter.excludeParameterName]; + + final Iterable excludeList; + if (raw is Iterable) { + excludeList = raw; + } else if (raw is String) { + excludeList = [raw]; + } else { + excludeList = []; + } return ExcludedIdentifiersListParameter.fromJson( excludeList: excludeList, diff --git a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart index db9bcef7..1f8ac88c 100644 --- a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart +++ b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart @@ -412,6 +412,40 @@ class _Test implements Test { final bool? test; const _Test({this.test}); } +'''); + } + + Future test_does_not_report_on_excluded_declaration_and_annotation_single_string() async { + final FakeAnalysisOptionsLoader fakeAnalysisOptionsLoader = + FakeAnalysisOptionsLoader( + ruleOptions: { + 'exclude': 'excludeMethod', + 'exclude_annotation': 'freezed', + }, + ); + + rule = AvoidUnusedParametersRule( + analysisOptionsLoader: fakeAnalysisOptionsLoader, + ); + + await assertNoDiagnostics(r''' +const freezed = Object(); + +@freezed +class Test { + const factory Test({ + bool test, + }) = _Test; +} + +class _Test implements Test { + final bool? test; + const _Test({this.test}); +} + +void excludeMethod(String s) { + return; +} '''); } } diff --git a/test/src/common/parameters/parameters_parsing_test.dart b/test/src/common/parameters/parameters_parsing_test.dart new file mode 100644 index 00000000..af4ace04 --- /dev/null +++ b/test/src/common/parameters/parameters_parsing_test.dart @@ -0,0 +1,78 @@ +import 'package:solid_lints/src/common/parameters/excluded_annotations_list_parameter.dart'; +import 'package:solid_lints/src/common/parameters/excluded_entities_list_parameter.dart'; +import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart'; +import 'package:test/test.dart'; + +void main() { + group('ExcludedAnnotationsListParameter', () { + test('parses list of strings', () { + final param = ExcludedAnnotationsListParameter.fromJson({ + 'exclude_annotation': ['MyAnnotation1', 'MyAnnotation2'], + }); + expect(param.excludedAnnotations, containsAll(['MyAnnotation1', 'MyAnnotation2'])); + }); + + test('parses single string', () { + final param = ExcludedAnnotationsListParameter.fromJson({ + 'exclude_annotation': 'MyAnnotation', + }); + expect(param.excludedAnnotations, contains('MyAnnotation')); + expect(param.excludedAnnotations.length, 1); + }); + + test('parses empty or invalid input', () { + final param = ExcludedAnnotationsListParameter.fromJson({}); + expect(param.excludedAnnotations, isEmpty); + }); + }); + + group('ExcludedEntitiesListParameter', () { + test('parses list of strings', () { + final param = ExcludedEntitiesListParameter.fromJson({ + 'exclude_entity': ['mixin', 'enum'], + }); + expect(param.excludedEntityNames, containsAll(['mixin', 'enum'])); + }); + + test('parses single string', () { + final param = ExcludedEntitiesListParameter.fromJson({ + 'exclude_entity': 'mixin', + }); + expect(param.excludedEntityNames, contains('mixin')); + expect(param.excludedEntityNames.length, 1); + }); + + test('parses empty or invalid input', () { + final param = ExcludedEntitiesListParameter.fromJson({}); + expect(param.excludedEntityNames, isEmpty); + }); + }); + + group('ExcludedIdentifiersListParameter', () { + test('parses list of strings and maps', () { + final param = ExcludedIdentifiersListParameter.defaultFromJson({ + 'exclude': [ + 'my_function', + {'class_name': 'MyClass', 'method_name': 'my_method'}, + ], + }); + expect(param.exclude.length, 2); + expect(param.exclude[0].declarationName, 'my_function'); + expect(param.exclude[1].className, 'MyClass'); + expect(param.exclude[1].methodName, 'my_method'); + }); + + test('parses single string', () { + final param = ExcludedIdentifiersListParameter.defaultFromJson({ + 'exclude': 'my_function', + }); + expect(param.exclude.length, 1); + expect(param.exclude[0].declarationName, 'my_function'); + }); + + test('parses empty or invalid input', () { + final param = ExcludedIdentifiersListParameter.defaultFromJson({}); + expect(param.exclude, isEmpty); + }); + }); +} From 1a0dc927dce708457267a259374f2f15d35ae425 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 15:40:52 +0300 Subject: [PATCH 3/7] feat: support checking inherited annotations for all declaration types in avoid_unused_parameters lint --- .../excluded_annotations_list_parameter.dart | 26 ++++++++++++++----- .../avoid_unused_parameters_rule_test.dart | 20 +++++++++++++- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/lib/src/common/parameters/excluded_annotations_list_parameter.dart b/lib/src/common/parameters/excluded_annotations_list_parameter.dart index 96faed08..4d1c87ee 100644 --- a/lib/src/common/parameters/excluded_annotations_list_parameter.dart +++ b/lib/src/common/parameters/excluded_annotations_list_parameter.dart @@ -34,16 +34,28 @@ class ExcludedAnnotationsListParameter { } /// Returns whether the target node should be ignored during analysis because - /// its enclosing class is annotated with one of the excluded annotations. + /// its enclosing declaration is annotated with one of the excluded + /// annotations. bool shouldIgnore(Declaration node) { if (excludedAnnotations.isEmpty) return false; - final classDecl = node.thisOrAncestorOfType(); - if (classDecl == null) return false; + AstNode? current = node; + while (current != null) { + if (current is ClassDeclaration || + current is MixinDeclaration || + current is EnumDeclaration || + current is ExtensionDeclaration || + current is ExtensionTypeDeclaration) { + final declaration = current as Declaration; + return declaration.metadata.any((annotation) { + final name = annotation.name.name; + final simpleName = name.split('.').last; + return excludedAnnotations.contains(simpleName); + }); + } + current = current.parent; + } - return classDecl.metadata.any((annotation) { - final name = annotation.name.name; - return excludedAnnotations.contains(name); - }); + return false; } } diff --git a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart index 1f8ac88c..725d3ba0 100644 --- a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart +++ b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart @@ -415,7 +415,8 @@ class _Test implements Test { '''); } - Future test_does_not_report_on_excluded_declaration_and_annotation_single_string() async { + Future + test_does_not_report_on_excluded_declaration_and_annotation_single_string() async { final FakeAnalysisOptionsLoader fakeAnalysisOptionsLoader = FakeAnalysisOptionsLoader( ruleOptions: { @@ -443,6 +444,23 @@ class _Test implements Test { const _Test({this.test}); } +class Meta { + const Meta(); +} +const meta = Meta(); + +@meta.freezed +class TestWithPrefix { + const factory TestWithPrefix({ + bool test, + }) = _TestWithPrefix; +} + +class _TestWithPrefix implements TestWithPrefix { + final bool? test; + const _TestWithPrefix({this.test}); +} + void excludeMethod(String s) { return; } From a16fe8e303267740f1bf3467335f037508d120a8 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 15:46:36 +0300 Subject: [PATCH 4/7] refactor: simplify excluded annotations check by iterating through all declarations --- .../excluded_annotations_list_parameter.dart | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/src/common/parameters/excluded_annotations_list_parameter.dart b/lib/src/common/parameters/excluded_annotations_list_parameter.dart index 4d1c87ee..4e52f1f6 100644 --- a/lib/src/common/parameters/excluded_annotations_list_parameter.dart +++ b/lib/src/common/parameters/excluded_annotations_list_parameter.dart @@ -41,17 +41,13 @@ class ExcludedAnnotationsListParameter { AstNode? current = node; while (current != null) { - if (current is ClassDeclaration || - current is MixinDeclaration || - current is EnumDeclaration || - current is ExtensionDeclaration || - current is ExtensionTypeDeclaration) { - final declaration = current as Declaration; - return declaration.metadata.any((annotation) { + if (current is Declaration) { + final hasAnnotation = current.metadata.any((annotation) { final name = annotation.name.name; final simpleName = name.split('.').last; return excludedAnnotations.contains(simpleName); }); + if (hasAnnotation) return true; } current = current.parent; } From 62599c302a9bd887946dad0daa5dec3d9285438f Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 16:11:37 +0300 Subject: [PATCH 5/7] feat: allow map values in exclude parameters, generalize Iterable parsing, and fix operator precedence in unused parameter visitor --- .../excluded_annotations_list_parameter.dart | 2 +- .../excluded_entities_list_parameter.dart | 2 +- .../excluded_identifiers_list_parameter.dart | 13 +++++-------- .../visitors/avoid_unused_parameters_visitor.dart | 4 ++-- .../common/parameters/parameters_parsing_test.dart | 9 +++++++++ 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/src/common/parameters/excluded_annotations_list_parameter.dart b/lib/src/common/parameters/excluded_annotations_list_parameter.dart index 4e52f1f6..81d0ed6a 100644 --- a/lib/src/common/parameters/excluded_annotations_list_parameter.dart +++ b/lib/src/common/parameters/excluded_annotations_list_parameter.dart @@ -18,7 +18,7 @@ class ExcludedAnnotationsListParameter { /// Method for creating from json data factory ExcludedAnnotationsListParameter.fromJson(Map json) { final raw = json[excludeAnnotationKey]; - if (raw is List) { + if (raw is Iterable) { return ExcludedAnnotationsListParameter( excludedAnnotations: Set.from(raw.whereType()), ); diff --git a/lib/src/common/parameters/excluded_entities_list_parameter.dart b/lib/src/common/parameters/excluded_entities_list_parameter.dart index 80e81bc9..c10b6793 100644 --- a/lib/src/common/parameters/excluded_entities_list_parameter.dart +++ b/lib/src/common/parameters/excluded_entities_list_parameter.dart @@ -22,7 +22,7 @@ class ExcludedEntitiesListParameter { /// Method for creating from json data factory ExcludedEntitiesListParameter.fromJson(Map json) { final raw = json['exclude_entity']; - if (raw is List) { + if (raw is Iterable) { return ExcludedEntitiesListParameter( excludedEntityNames: Set.from(raw.whereType()), ); diff --git a/lib/src/common/parameters/excluded_identifiers_list_parameter.dart b/lib/src/common/parameters/excluded_identifiers_list_parameter.dart index 0b769b61..484c49cc 100644 --- a/lib/src/common/parameters/excluded_identifiers_list_parameter.dart +++ b/lib/src/common/parameters/excluded_identifiers_list_parameter.dart @@ -45,14 +45,11 @@ class ExcludedIdentifiersListParameter { ) { final raw = json[ExcludedIdentifiersListParameter.excludeParameterName]; - final Iterable excludeList; - if (raw is Iterable) { - excludeList = raw; - } else if (raw is String) { - excludeList = [raw]; - } else { - excludeList = []; - } + final excludeList = switch (raw) { + Iterable() => raw, + Map() || String() => [raw], + _ => const [], + }; return ExcludedIdentifiersListParameter.fromJson( excludeList: excludeList, 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 3dac3e66..31cb12ad 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 @@ -45,7 +45,7 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { final parent = node.parent; final parameters = node.parameters; - if (parent is ClassDeclaration && parent.abstractKeyword != null || + if ((parent is ClassDeclaration && parent.abstractKeyword != null) || node.externalKeyword != null || node.redirectedConstructor != null || _hasExcludedAnnotationClass(node) || @@ -73,7 +73,7 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { final parent = node.parent; final parameters = node.parameters; - if (parent is ClassDeclaration && parent.abstractKeyword != null || + if ((parent is ClassDeclaration && parent.abstractKeyword != null) || node.isAbstract || node.externalKeyword != null || (parameters == null || parameters.parameters.isEmpty)) { diff --git a/test/src/common/parameters/parameters_parsing_test.dart b/test/src/common/parameters/parameters_parsing_test.dart index af4ace04..f64d303a 100644 --- a/test/src/common/parameters/parameters_parsing_test.dart +++ b/test/src/common/parameters/parameters_parsing_test.dart @@ -70,6 +70,15 @@ void main() { expect(param.exclude[0].declarationName, 'my_function'); }); + test('parses single map', () { + final param = ExcludedIdentifiersListParameter.defaultFromJson({ + 'exclude': {'class_name': 'MyClass', 'method_name': 'my_method'}, + }); + expect(param.exclude.length, 1); + expect(param.exclude[0].className, 'MyClass'); + expect(param.exclude[0].methodName, 'my_method'); + }); + test('parses empty or invalid input', () { final param = ExcludedIdentifiersListParameter.defaultFromJson({}); expect(param.exclude, isEmpty); From 89ae71502930c04710fcdbafafdcec3261ceaa68 Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 18:20:34 +0300 Subject: [PATCH 6/7] test: simplify freezed class definitions in avoid_unused_parameters test cases --- .../avoid_unused_parameters_rule_test.dart | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart index 725d3ba0..ab627276 100644 --- a/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart +++ b/test/lints/avoid_unused_parameters/avoid_unused_parameters_rule_test.dart @@ -403,14 +403,7 @@ const freezed = Object(); @freezed class Test { - const factory Test({ - bool test, - }) = _Test; -} - -class _Test implements Test { - final bool? test; - const _Test({this.test}); + const Test(int unusedParameter); } '''); } @@ -434,14 +427,7 @@ const freezed = Object(); @freezed class Test { - const factory Test({ - bool test, - }) = _Test; -} - -class _Test implements Test { - final bool? test; - const _Test({this.test}); + const Test(int unusedParameter); } class Meta { @@ -451,14 +437,7 @@ const meta = Meta(); @meta.freezed class TestWithPrefix { - const factory TestWithPrefix({ - bool test, - }) = _TestWithPrefix; -} - -class _TestWithPrefix implements TestWithPrefix { - final bool? test; - const _TestWithPrefix({this.test}); + const TestWithPrefix(int unusedParameter); } void excludeMethod(String s) { From 07f3df7c310f3d6cfa1220f26c4f715550b18a7e Mon Sep 17 00:00:00 2001 From: Illia Aihistov Date: Fri, 3 Jul 2026 18:26:43 +0300 Subject: [PATCH 7/7] fix: allow excluded annotations to be matched by full qualified name --- .../common/parameters/excluded_annotations_list_parameter.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/common/parameters/excluded_annotations_list_parameter.dart b/lib/src/common/parameters/excluded_annotations_list_parameter.dart index 81d0ed6a..2f740d92 100644 --- a/lib/src/common/parameters/excluded_annotations_list_parameter.dart +++ b/lib/src/common/parameters/excluded_annotations_list_parameter.dart @@ -45,7 +45,8 @@ class ExcludedAnnotationsListParameter { final hasAnnotation = current.metadata.any((annotation) { final name = annotation.name.name; final simpleName = name.split('.').last; - return excludedAnnotations.contains(simpleName); + return excludedAnnotations.contains(name) || + excludedAnnotations.contains(simpleName); }); if (hasAnnotation) return true; }