void-checks
Same as void_checks in Dart lints
- Group
- Correctness
- Path
lint/correctness/void-checks- Default
- On (recommended)
- Origin
- Dart lints
- Rule
- 511 of 512
Don't pass or assign values to void (or FutureOr<void>) locations.
void accept<T>(T value) {}
accept<void>(1); // BAD
accept<void>(null); // GOOD
Arguments of direct function, method, and constructor invocations, assignments
(including assigned-variable patterns and cascades), and index assignments
are checked against the instantiated parameter type, including receiver and
inferred method type arguments in cascade calls: a void location accepts only
void, Null, Never, and Futures of those; a FutureOr<void> location
additionally accepts dynamic and any FutureOr or Future of an
acceptable type. Only block-bodied function literals have their inferred
return type checked, inferring the literal against the location's type;
expression bodies and tear-offs are not checked as callbacks. Return
statements use the enclosing function's return type (a function literal's
inferred one, not its context); returning to void is checked only for a
dynamic value. Assignments and returns report at the whole statement,
arguments at the value expression.
Calls through function-valued variables, fields, and getters are excluded;
an explicit .call(...) remains a method invocation and is checked.
Grouped callees, including instantiated generic tear-offs, remain excluded;
grouping a direct invocation does not exclude the invocation itself.
Unresolved values stay silent.
Invalid
import 'dart:async';
void accept<T>(T value) {}
void acceptFuture<T>(Future<T> value) {}
void acceptFutureOr<T>(FutureOr<T> value) {}
void acceptCallback<T>(T Function() callback) {}
int makeInt() => 1;
class Box<T> {
Box(T value);
T field;
void setValue(T value) {}
}
void bad(Future<int> integerFuture) {
accept<void>(1);
accept<void>(makeInt());
acceptFutureOr<void>('text');
Box<void>(1);
Box<void> box = Box<void>(null);
box.setValue(1);
box.field = 1;
List<void> list = [];
list.add(1);
list[0] = 1;
}
// Analyzer 3.13.5: adv-AdvB/repro/vc_local.dart and vc_misc.dart.
void voidLocal(dynamic value) {
void local;
local = 1;
local = value;
}
void voidPatterns(void parameter) {
[parameter] = <int>[7];
(parameter, _) = (1, 2);
}
class VoidLocations<T> {
set value(T value) {}
static void accept(void value) {}
set dynamicReturn(dynamic value) {
return value;
}
}
extension VoidExtension on int {
void accept(void value) {}
}
void voidCalls(void Function(void) callback, dynamic value) {
VoidLocations<void>().value = 1;
VoidLocations.accept(1);
callback.call(1);
VoidExtension(1).accept(value);
}void bad(Future<int> integerFuture) { accept<void>(1); accept<void>(1); accept<void>(makeInt()); accept<void>(makeInt()); acceptFutureOr<void>('text'); acceptFutureOr<void>('text'); Box<void>(1); Box<void> box = Box<void>(null); box.setValue(1); box.setValue(1); box.field = 1; List<void> list = []; list.add(1); list.add(1); list[0] = 1; void local; local = 1; local = 1; local = value;void voidPatterns(void parameter) { [parameter] = <int>[7]; [parameter] = <int>[7]; (parameter, _) = (1, 2); set dynamicReturn(dynamic value) { return value;void voidCalls(void Function(void) callback, dynamic value) { VoidLocations<void>().value = 1; VoidLocations<void>().value = 1; VoidLocations.accept(1); VoidLocations.accept(1); callback.call(1); callback.call(1); VoidExtension(1).accept(value);Valid
import 'dart:async';
void accept<T>(T value) {}
void acceptFuture<T>(Future<T> value) {}
void acceptFutureOr<T>(FutureOr<T> value) {}
void acceptCallback<T>(T Function() callback) {}
class Box<T> {
Box(T value);
T field;
void setValue(T value) {}
}
void ordinaryVoid() {
return;
}
void good(
Future<int> integerFuture,
Future<void> voidFuture,
Future<Null> nullFuture,
dynamic dynamicValue,
) {
accept<void>(null);
acceptFuture<void>(voidFuture);
acceptFuture<void>(nullFuture);
acceptFutureOr<void>(voidFuture);
acceptFutureOr<void>(dynamicValue);
acceptCallback<void>(() => null);
Box<void> box = Box<void>(null);
box.setValue(null);
box.field = null;
// Only `void` and `FutureOr<void>` locations are checked.
acceptFuture<void>(integerFuture);
// Function literals are inferred against their `void Function()` context,
// and function-typed locations never conflict.
acceptCallback<void>(() => 1);
acceptCallback<void>(() { return 'x'; });
final inferredCallback = () => 3;
acceptCallback<void>(inferredCallback);
acceptCallback<void>(() {
if (true) {
return 'nested';
}
for (final value in <int>[1]) {
print(value);
return 2;
}
return null;
});
}Configure void-checks
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"void-checks": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/void-checks: <reason>More correctness rules
- add-equatable-propsrecommendedequatable
Flags concrete Equatable subclasses that do not declare an instance props property.
- always-pass-global-keyflutter
Keep
GlobalKeysstable and pass owned State fields to widgets. - always-remove-listenerrecommendedflutter
Requires Flutter Listenable registrations in State to be removed.
- always-use-package-imports
always_use_package_importsDisallow relative imports in libraries under a package's
lib/directory. - avoid-assigning-to-static-field
Flags instance methods writing resolved static fields, including compound assignments and increments.
- avoid-calling-notifier-members-inside-buildrecommendedriverpod
Flags calls to Riverpod notifier methods during widget build.
- avoid-collection-equality-checksrecommended
Flags equality comparisons between non-constant SDK collections.
- avoid-conditional-hooksrecommendedflutter_hooks
Flags hook calls in conditional branches, short-circuit operands, and loops.