Create rule S7104: Generic function type syntax should be preferred for parameters (use_function_type_syntax_for_parameters) (#4344)

Co-authored-by: antonioaversa <antonioaversa@users.noreply.github.com>
This commit is contained in:
github-actions[bot] 2024-10-01 14:21:56 +02:00 committed by GitHub
parent b7cd8c2b52
commit b7b99233f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 148 additions and 0 deletions

View File

@ -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"
}
}

122
rules/S7104/dart/rule.adoc Normal file
View File

@ -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<int> y`, `Map<String, double>? 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 '<parameterName>'.
=== Highlighting
The entire parameter declaration, comprising the type and the name of the parameter: e.g. `bool p(T)` in `Iterable<T> f1(bool p(T), int i1) => [];`.
endif::env-github,rspecator-view[]

View File

@ -0,0 +1,2 @@
{
}