avoid-unsafe-reduce
- Group
- Correctness
- Path
lint/correctness/avoid-unsafe-reduce- Default
- Off, opt in
- Origin
- Falcon
- Rule
- 181 of 512
Warn when SDK Iterable.reduce can receive an empty collection.
Constant nonempty collections and fresh literals with an unconditional element are safe, including reduce as the first cascade operation. Immediate isEmpty/isNotEmpty branches require a local or final-field receiver and no intervening expression that can mutate it. Custom reduce members and unresolved receivers are excluded.
Invalid
int sum(int a, int b) => a + b;
void unsafe(List<int> list, Set<int> set, Iterable<int> iterable, List<int>? nullable) {
list.reduce(sum);
set.reduce((a, b) => a + b);
iterable.reduce(sum);
nullable?.reduce(sum);
<int>[].reduce(sum);
list..reduce(sum);
if (list.isNotEmpty) {
list.clear();
list.reduce((a, b) => a + b);
}
}
int mutatingCallback(List<int> list) {
int Function(int, int) callback() {
list.clear();
return sum;
}
return list.isNotEmpty ? list.reduce(callback()) : 0;
}
var reads = 0;
List<int> get values => reads++ == 0 ? [1] : [];
int unstableGetter() =>
values.isNotEmpty ? values.reduce((a, b) => a + b) : 0;
void mutatedCascades() {
[1, 2]..clear()..reduce(sum);
[1, 2]..length = 0..reduce(sum);
}
class UnstableReceiver {
List<int> values = [];
List<int> get items => [];
int field() =>
values.isNotEmpty ? values.reduce(sum) : 0;
int getter() =>
items.isNotEmpty ? items.reduce(sum) : 0;
}
class StaticReceiver {
static List<int> values = [];
int sum() =>
values.isNotEmpty ? values.reduce((a, b) => a + b) : 0;
}
abstract class AbstractReceiver {
abstract final List<int> values;
int sum() =>
values.isNotEmpty ? values.reduce((a, b) => a + b) : 0;
}
extension EmptyingRead on List<int> {
int get empty {
clear();
return 0;
}
}
void getterCascade() {
[1]..empty..reduce(sum);
[1, 2]..length..reduce(sum);
}void unsafe(List<int> list, Set<int> set, Iterable<int> iterable, List<int>? nullable) { list.reduce(sum); list.reduce(sum); set.reduce((a, b) => a + b); set.reduce((a, b) => a + b); iterable.reduce(sum); iterable.reduce(sum); nullable?.reduce(sum); nullable?.reduce(sum); <int>[].reduce(sum); <int>[].reduce(sum); list..reduce(sum); list.clear(); list.reduce((a, b) => a + b); } return list.isNotEmpty ? list.reduce(callback()) : 0;int unstableGetter() => values.isNotEmpty ? values.reduce((a, b) => a + b) : 0;void mutatedCascades() { [1, 2]..clear()..reduce(sum); [1, 2]..clear()..reduce(sum); [1, 2]..length = 0..reduce(sum); int field() => values.isNotEmpty ? values.reduce(sum) : 0; int getter() => items.isNotEmpty ? items.reduce(sum) : 0; int sum() => values.isNotEmpty ? values.reduce((a, b) => a + b) : 0; int sum() => values.isNotEmpty ? values.reduce((a, b) => a + b) : 0;void getterCascade() { [1]..empty..reduce(sum); [1]..empty..reduce(sum); [1, 2]..length..reduce(sum);Valid
class Custom {
int reduce(int Function(int, int) combine) => 0;
}
int safe(List<int> list, Custom custom, dynamic unknown) {
custom.reduce((a, b) => a + b);
unknown.reduce((a, b) => a + b);
[1, 2].reduce((a, b) => a + b);
<int>{1}.reduce((a, b) => a + b);
[1, 2]..reduce((a, b) => a + b);
<int>{1}..reduce((a, b) => a + b);
const values = [1, 2];
values.reduce((a, b) => a + b);
list.fold<int>(0, (a, b) => a + b);
if (list.isNotEmpty) {
return list.reduce((a, b) => a + b);
}
return 0;
}
int guarded(List<int> list) => list.isEmpty ? 0 : list.reduce((a, b) => a + b);
int negated(List<int> list) {
if (!list.isEmpty) return list.reduce((a, b) => a + b);
return 0;
}
extension CustomReduce on String {
String reduce(String Function(String, String) combine) => this;
}
String customExtension(String value) => value.reduce((a, b) => a + b);
class StableReceiver {
final List<int> values;
StableReceiver(this.values);
int sum() => values.isNotEmpty ? values.reduce((a, b) => a + b) : 0;
}
void nonemptyCascadeSections() {
const values = [1, 2];
values..reduce((a, b) => a + b);
}Configure avoid-unsafe-reduce
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"avoid-unsafe-reduce": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/avoid-unsafe-reduce: <reason>More correctness rules
- avoid-unused-after-null-check
Reports a null-checked local ignored by a branch that passes another local of the same resolved type to a call.
- avoid-unused-parameters
avoid-unused-parametersrecommendedDisallow declared parameters that are never used, excluding primary constructors.
- avoid-watch-outside-buildrecommendedprovider
Flags listening Provider accesses proven to run outside Flutter builds.
- avoid-web-libraries-in-flutter
avoid_web_libraries_in_flutterrecommendedflutterDisallow importing web-only
dart:libraries from Flutter code. - await-only-futures
await_only_futuresrecommendedAwait only values assignable to futures;
FutureOr, dynamic, bottom types and extension types are accepted like the analyzer. - banned-importscross-file
Report imports forbidden by package-relative architectural boundaries.
- cancel-subscriptions
cancel_subscriptionsrecommendedCancel instances of
dart:asyncStreamSubscription. - check-is-not-closed-after-async-gaprecommendedbloc
Flags Bloc
addandemitcalls after an await without a freshisClosedcheck.