diff --git a/rules/S7104/dart/metadata.json b/rules/S7104/dart/metadata.json new file mode 100644 index 0000000000..101772249f --- /dev/null +++ b/rules/S7104/dart/metadata.json @@ -0,0 +1,24 @@ +{ + "title": "Generic function type syntax should be preferred for parameters", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "3min" + }, + "tags": [ + "brain-overload" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-7104", + "sqKey": "S7104", + "scope": "All", + "defaultQualityProfiles": ["Sonar way"], + "quickfix": "unknown", + "code": { + "impacts": { + "MAINTAINABILITY": "HIGH" + }, + "attribute": "CLEAR" + } +} diff --git a/rules/S7104/dart/rule.adoc b/rules/S7104/dart/rule.adoc new file mode 100644 index 0000000000..a6a125e19b --- /dev/null +++ b/rules/S7104/dart/rule.adoc @@ -0,0 +1,122 @@ +Function parameters of type "function" should be declared using generic function type syntax. + +== Why is this an issue? + +There are two ways of defining a function or method parameter type, when such type is a flavor of `Function` that needs to be defined inline: + +* using the *generic function syntax*: `void Function(int) parameterName` +* using the *legacy function syntax*: `void parameterName(int)` + +The first option should be preferred in all circumstances, for the following reasons: + +* readability +* consistency + +=== Readability + +Unlike non-`Function` type, which always preceed the parameter name (e.g. `int x`, `List y`, `Map? z`, etc.), `Function` types expressed using the legacy syntax are intermingled with the parameter name. +Specifically, part of the type, namely the return type of the `Function`, is placed before the parameter name, whereas the list of formal parameters of the `Function` is placed after. + +[source,dart] +---- +void aFunction(void parameterName(int functionParameterName)) { + // ... +} +---- + +That makes the code harder to read and understand. For instance, it's not easy to tell at a first glance that `functionParameterName` is _not_ a parameter of `aFunction`, but a parameter of the `Function` parameter `parameterName` of `aFunction`. + +=== Consistency + +Pretty much like the function syntax, also the `typedef` syntax has two forms: + +* the *generic `typedef` syntax*: `typedef void MyFunction(int);` +* the *legacy `typedef` syntax*: `typedef MyFunction = void Function(int);` + +The first option is more powerful and flexible, as explained in S5416. + +The generic `typedef` syntax matches syntactically the generic function syntax defined inline. Using syntaxes consistently allows easier code maintenance and refactoring. + +For example if an inline generic function syntax needs to be extracted into a generic `typedef` syntax, for its complexity, number of occurrences, or to be exposed outside the current library, the refactoring is easier and less error-prone, since the right-end side of the `typedef` is the same as the inline type definition. + +[source,dart] +---- +// Before extraction of typedef using generic syntax +void aFunction(void Function(int functionParameterName) parameterName) { + // ... +} + +// After extraction of typedef using generic syntax +typedef MyFunction = void Function(int functionParameterName); +void aFunction(MyFunction parameterName) { + // ... +} +---- + +The same is not true for the legacy syntax: + +[source,dart] +---- +// Before extraction of typedef using legacy syntax +void aFunction(void parameterName(int functionParameterName)) { + // ... +} + +// After extraction of typedef using legacy syntax +typedef void MyFunction(int functionParameterName); +void aFunction(MyFunction parameterName) { + // ... +} +---- + +== How to fix it + +Replace the parameter name with the `Function` identifier. Move the parameter name after the list of formal parameters of the `Function`. + +=== Code examples + +==== Noncompliant code example + +[source,dart,diff-id=1,diff-type=noncompliant] +---- +void aFunction(void parameterName(int functionParameterName)) { + // ... +} +---- + +==== Compliant solution + +[source,dart,diff-id=1,diff-type=compliant] +---- +void aFunction(void Function(int functionParameterName) parameterName) { + // ... +} +---- + +== Resources + +=== Documentation + +* Dart Docs - https://dart.dev/tools/linter-rules/use_function_type_syntax_for_parameters[Dart Linter rule - use_function_type_syntax_for_parameters] +* Dart Docs - https://dart.dev/language/typedefs[Language - Typedefs] + +=== Related rules + +* S5416 - Generic function type aliases should be preferred + + +ifdef::env-github,rspecator-view[] + +''' +== Implementation Specification +(visible only on this page) + +=== Message + +Use the generic function type syntax to declare the parameter ''. + +=== Highlighting + +The entire parameter declaration, comprising the type and the name of the parameter: e.g. `bool p(T)` in `Iterable f1(bool p(T), int i1) => [];`. + +endif::env-github,rspecator-view[] diff --git a/rules/S7104/metadata.json b/rules/S7104/metadata.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/rules/S7104/metadata.json @@ -0,0 +1,2 @@ +{ +}