rspec/rules/S7090/dart/rule.adoc

105 lines
3.2 KiB
Plaintext

Chaining list(s) to a list literal via https://api.dart.dev/stable/dart-core/List/addAll.html[`List<E>.addAll`] should be replaced by a literal with the https://dart.dev/language/operators#spread-operators[spread operator] (``++...++``).
== Why is this an issue?
Chaining list(s) to a list literal via `addAll`, e.g. ``++[42]..addAll(l1)..addAll(l1);++``, is both less efficient and less verbose than using a list literal with the spread operator: ``++[42, ...l1, ...l1]++``.
* `addAll` chains can be less efficient because each `addAll` call is treated as a separate method call, resulting in unnecessary invocations and allocations, when the goal is to build a single list with all the items provided as arguments
* `addAll` chains are generally more verbose and less clear because spreading a list can be done via dedicate syntax (``++...++``) which is closer to natural language
The rule also applies when the chained list is a https://dart.dev/language/operators#conditional-expressions[conditional expression], because the spread operator can be applied conditionally:
[source,dart]
----
[42]..addAll(i1 == i2 ? [43, 44] : []); // Noncompliant
[42, if (i1 == i2) ...[43, 44]]; // Compliant
----
=== Exceptions
The rule doesn't apply when the list chained is a literal, because S7089 already covers this case.
[source,dart]
----
[]..addAll([42]); // Not applicable
----
The rule doesn't cover https://dart.dev/language/collections#control-flow-operators[if and for collections] either, for the same reason (S7089 covers it).
[source,dart]
----
[42]..addAll([if (i1 == 42) 43, 44]); // Not applicable
[42]..addAll([for (final i in [1, 2, 3]) i * i]); // Not applicable
----
The rule doesn't apply when the `addAll` is not called via cascade operator, but via standard dereference (`.`):
[source,dart]
----
[].addAll(l1); // Not applicable
[]..addAll(l1); // Noncompliant
----
== How to fix it
Take advantage of the spread operator and, if needed, of its capacity to be applied conditionally.
=== Code examples
==== Noncompliant code example
[source,dart,diff-id=1,diff-type=noncompliant]
----
[42]..addAll(aList)..addAll(anotherList);
----
==== Compliant solution
[source,dart,diff-id=1,diff-type=compliant]
----
[42, ...aList, ...anotherList];
----
==== Noncompliant code example
[source,dart,diff-id=2,diff-type=noncompliant]
----
[42]..addAll(i1 == i2 ? [43, 44] : []);
----
==== Compliant solution
[source,dart,diff-id=2,diff-type=compliant]
----
[42, if (i1 == i2) ...[43, 44]];
----
== Resources
=== Documentation
* Dart Docs - https://dart.dev/tools/linter-rules/prefer_spread_collections[Dart Linter rule - prefer_spread_collections]
* Dart Docs - https://dart.dev/language/operators#spread-operators[Language - Spread operators]
* Dart API Reference - https://api.dart.dev/stable/dart-core/List/addAll.html[`List<E>.addAll`]
=== Related rules
* S3257 - Collection literals should be preferred
* S7089 - Inline list literals should be preferred to chains of insertions
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
The addition of multiple elements could be inlined.
=== Highlighting
The first method invocation in the chain of `addAll` invocations.
endif::env-github,rspecator-view[]