rspec/rules/S7107/dart/rule.adoc

185 lines
4.7 KiB
Plaintext

A constructor that forwards all its parameters to a https://dart.dev/language/constructors#non-default-superclass-constructors[superclass constructor] should use https://dart.dev/language/constructors#super-parameters[`super` parameters] (e.g. `ConstructorName(super.field)`) instead of manually forwarding each parameter (as in `ConstructorName(int field) : super(field)`).
== Why is this an issue?
In Dart, constructors can "forward" their parameters to a constructor of the parent class, using the `super` keyword.
[source,dart]
----
class ComplexNumber {
final double real;
final double imaginary;
const ComplexNumber(this.real, this.imaginary);
}
class RealNumber extends ComplexNumber {
const RealNumber(double real) : super(real, 0); // Forwards the `real` parameter
}
----
When a constructor forwards all its parameters to a superclass constructor, and does not alter them in any way, it is recommended to use https://dart.dev/language/constructors#super-parameters[`super` parameters] instead of manually forwarding each parameter.
[source,dart]
----
class Point {
final int x;
final int y;
const Point(this.x, this.y);
}
class ThreeDPoint extends Point {
final int z;
const ThreeDPoint(super.x, super.y, this.z);
}
----
=== What is the potential impact?
Manually forwarding parameters is more verbose. It can also be error-prone. For instance, if the superclass constructor has multiple parameters of the same type, there is the risk of mixing them up:
[source,dart]
----
class Parent {
final int field1;
final int field2;
const Parent(this.field1, this.field2);
}
class Child extends Parent {
const Child(int field2, int field1) : super(field2, field1); // Wrong order
}
----
This cannot happen with `super` parameters, no matter what is the order of parameters declared in the `Child` class, as they are matched by name.
=== Exceptions
The rule doesn't apply if parameters are altered before being passed to the superclass constructor.
For example, if they need to be swapped:
[source,dart]
----
class Child extends Parent {
const Child(int field1, int field2) : super(field2, field1); // Non applicable
}
----
or their values transformed:
[source,dart]
----
class Child extends Parent {
const Child(int field1, int field2) : super(field1 + field2, field1 - field2); // Non applicable
}
----
On the other hand, changing the type of the parameter in the subclass with a compatible one is not considered a transformation, so the rule applies:
[source,dart]
----
class Child extends Parent {
const Child(dynamic field1, dynamic field2) : super(field1, field2); // Non compliant
}
----
Similarly, the rule applies if the parameter has a different name in the child class:
[source,dart]
----
class Child extends Parent {
const Child(int field3, int field4) : super(field3, field4); // Non compliant
}
----
However, it's enough for a single parameter to be altered for the rule to be considered as not applicable:
[source,dart]
----
class Child extends Parent {
Child(int field1) : super(field1, field1.hashCode); // Non applicable
}
----
That includes swapping them:
[source,dart]
----
class Child extends Parent {
Child(int field1, int field2) : super(field2, field1); // Non applicable
}
----
== How to fix it
Remove the call to the superclass constructor and replace normal parameters with `super` parameters, matching the names of the parameter in the parent class.
=== Code examples
==== Noncompliant code example
[source,dart,diff-id=1,diff-type=noncompliant]
----
class Point {
final int x;
final int y;
const Point(this.x, this.y);
}
class ThreeDPoint extends Point {
final int z;
const ThreeDPoint(int x, int y, this.z): super(x, y);
}
----
==== Compliant solution
[source,dart,diff-id=1,diff-type=compliant]
----
class Point {
final int x;
final int y;
const Point(this.x, this.y);
}
class ThreeDPoint extends Point {
final int z;
const ThreeDPoint(super.x, super.y, this.z);
}
----
== Resources
=== Documentation
* Dart Docs - https://dart.dev/tools/linter-rules/use_super_parameters[Dart Linter rule - use_super_parameters]
* Dart Docs - https://dart.dev/language/constructors#non-default-superclass-constructors[Language - Non-default superclass constructors]
* Dart Docs - https://dart.dev/language/constructors#super-parameters[Language - Super parameters]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
* Parameters '<parameterName>' could be super parameter.
* Parameters '<parameterName1>' and '<parameterName2>' could be super parameters.
* Parameters '<parameterName1>' (, '<parameterNameI>')+, and '<parameterNameN>' could be super parameters.
=== Highlighting
The identifier of the constructor at the declaration site.
endif::env-github,rspecator-view[]