diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb9eaf..3eba677 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - 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. - 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 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 1770e00..e48a311 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 @@ -9,6 +9,14 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// ### Example: /// #### BAD: /// ```dart +/// typedef MaxFun = int Function(int a, int b); +/// final MaxFun bad = (int a, int b) => 1; // LINT +/// final MaxFun testFun = (int a, int b) { // LINT +/// return 4; +/// }; +/// final optional = (int a, [int b = 0]) { // LINT +/// return a; +/// }; /// void fun(String x) {} // LINT /// void fun2(String x, String y) { // LINT /// print(y); @@ -27,6 +35,11 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// /// #### GOOD: /// ```dart +/// typedef MaxFun = int Function(int a, int b); +/// final MaxFun good = (int a, int b) => a + b; +/// final MaxFun testFun = (int a, int b) { +/// return a + b; +/// }; /// void fun(String _) {} // Replacing with underscores silences the warning /// void fun2(String _, String y) { /// print(y); @@ -42,6 +55,15 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart'; /// } /// } /// ``` +/// +/// #### Allowed: +/// ```dart +/// typedef Named = String Function({required String text}); +/// final Named named = ({required text}) { +/// return ''; +/// }; +/// +/// ``` class AvoidUnusedParametersRule extends SolidLintRule { /// The [LintCode] of this lint rule that represents /// the error whether we use bad formatted double literals. diff --git a/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_visitor.dart b/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_visitor.dart index 284521c..40b19f2 100644 --- a/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_visitor.dart +++ b/lib/src/lints/avoid_unused_parameters/avoid_unused_parameters_visitor.dart @@ -48,13 +48,14 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { parameters.parameters.isEmpty) { return; } + final unused = _getUnusedParameters( + node.body, + parameters.parameters, + initializers: node.initializers, + ).whereNot(nameConsistsOfUnderscoresOnly); _unusedParameters.addAll( - _getUnusedParameters( - node.body, - parameters.parameters, - initializers: node.initializers, - ).whereNot(nameConsistsOfUnderscoresOnly), + unused, ); } @@ -76,31 +77,41 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { if (!isOverride(node.metadata) && !isTearOff) { _unusedParameters.addAll( - _getUnusedParameters( + _filterOutUnderscoresAndNamed( node.body, parameters.parameters, - ).whereNot(nameConsistsOfUnderscoresOnly), + ), ); } } @override - void visitFunctionDeclaration(FunctionDeclaration node) { - super.visitFunctionDeclaration(node); - - final parameters = node.functionExpression.parameters; - - if (node.externalKeyword != null || - (parameters == null || parameters.parameters.isEmpty)) { + void visitFunctionExpression(FunctionExpression node) { + super.visitFunctionExpression(node); + final params = node.parameters; + if (params == null) { return; } _unusedParameters.addAll( - _getUnusedParameters( - node.functionExpression.body, - parameters.parameters, - ).whereNot(nameConsistsOfUnderscoresOnly), + _filterOutUnderscoresAndNamed( + node.body, + params.parameters, + ), + ); + } + + Iterable _filterOutUnderscoresAndNamed( + AstNode body, + Iterable parameters, + ) { + final unused = _getUnusedParameters( + body, + parameters, ); + return unused.whereNot(nameConsistsOfUnderscoresOnly).where( + (param) => !param.isNamed, + ); } Set _getUnusedParameters( @@ -134,6 +145,7 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor { isFieldFormalParameter = parameter.toSource().contains('this.'); isSuperFormalParameter = parameter.toSource().contains('super.'); } + // if (name != null && !isPresentInAll && diff --git a/lint_test/avoid_unused_parameters_test.dart b/lint_test/avoid_unused_parameters_test.dart index 4d3950f..b75e120 100644 --- a/lint_test/avoid_unused_parameters_test.dart +++ b/lint_test/avoid_unused_parameters_test.dart @@ -1,4 +1,4 @@ -// ignore_for_file: prefer_const_declarations, prefer_match_file_name +// ignore_for_file: prefer_const_declarations, prefer_match_file_name, avoid_global_state // ignore_for_file: unnecessary_nullable_for_final_variable_declarations // ignore_for_file: unused_local_variable // ignore_for_file: unused_element @@ -9,12 +9,79 @@ import 'package:flutter/material.dart'; /// Check the `avoid_unused_parameters` rule +/// +void testNamed() { + SomeAnotherClass( + func: ({required text}) {}, + ); +} + +typedef MaxFun = int Function(int a, int b); + +typedef Named = String Function({required String text}); + +typedef ReqNamed = void Function({required String text}); + +// expect_lint: avoid_unused_parameters +final MaxFun bad = (int a, int b) => 1; + +final MaxFun good = (int a, _) => a; + +final MaxFun ok = (int _, int __) => 1; + +final MaxFun goodMax = (int a, int b) { + return a + b; +}; + +final Named _named = ({required text}) { + return ''; +}; + +void ch({String text = ''}) {} + +final Named _named2 = ({required text}) { + return text; +}; + +final Named _named3 = ({required text}) => ''; + +final Named _named4 = ({required text}) => text; + +// expect_lint: avoid_unused_parameters +final optional = (int a, [int b = 0]) { + return a; +}; + +// expect_lint: avoid_unused_parameters +final named = (int a, {required int b, int c = 0}) { + return c; +}; + +// good +var k = (String g) { + return g; +}; + +// expect_lint: avoid_unused_parameters +var c = (String g) { + return '0'; +}; + +// expect_lint: avoid_unused_parameters +final MaxFun tetsFun = (int a, int b) { + return 4; +}; // expect_lint: avoid_unused_parameters void fun(String s) { return; } +// expect_lint: avoid_unused_parameters +void fun2(String s) { + return; +} + class TestClass { // expect_lint: avoid_unused_parameters static void staticMethod(int a) {} @@ -34,6 +101,14 @@ class TestClass2 { } class SomeOtherClass { + // expect_lint: avoid_unused_parameters + final MaxFun maxFunLint = (int a, int b) => 1; + + // Good + final MaxFun good = (int a, int b) { + return a * b; + }; + // expect_lint: avoid_unused_parameters void method(String s) { return; @@ -41,6 +116,12 @@ class SomeOtherClass { } class SomeAnotherClass extends SomeOtherClass { + final ReqNamed func; + + SomeAnotherClass({ + required this.func, + }); + @override void method(String s) {} } @@ -67,11 +148,11 @@ void closure(int a) { } } -typedef MaxFun = int Function(int a, int b); - -// Allowed same way as override +// expect_lint: avoid_unused_parameters final MaxFun maxFunInstance = (int a, int b) => 1; +final MaxFun m = (_, __) => 1; + class Foo { final int a; final int? b; @@ -102,8 +183,15 @@ class TestWidget extends StatelessWidget { super.key, // expect_lint: avoid_unused_parameters int a = 1, + // expect_lint: avoid_unused_parameters + String k = '', }); + // expect_lint: avoid_unused_parameters + factory TestWidget.a([int b = 0]) { + return TestWidget(k: ''); + } + @override Widget build(BuildContext context) { return const Placeholder();