use-build-context-synchronously
Same as use_build_context_synchronously in Dart lints
- Group
- Correctness
- Path
lint/correctness/use-build-context-synchronously- Default
- On (recommended)
- Origin
- Dart lints
- Domain
- flutter
- Rule
- 482 of 512
Flags BuildContext use after an asynchronous gap without a mounted guard.
A mounted guard must check the same BuildContext used after the gap.
Function bodies are checked independently; callbacks passed to SDK async APIs
that guarantee a mounted context are exempt.
Invalid
import 'package:flutter/widgets.dart';
Future<void> work() async {}
Future<bool> ready() async => true;
Object? consume(BuildContext context) => null;
Future<void> unguarded(BuildContext context) async {
await work();
context.toString();
}
Future<void> wrongGuard(BuildContext context, BuildContext other) async {
await work();
if (!other.mounted) return;
context.toString();
}
Future<void> guardRhs(BuildContext context) async {
await work();
if (context.mounted || consume(context) == null) {}
if (!context.mounted && consume(context) == null) {}
}
Future<void> loopBackedge(BuildContext context, bool keepGoing) async {
while (keepGoing) {
context.toString();
await work();
}
}
Future<void> forUpdate(BuildContext context, bool keepGoing) async {
for (; keepGoing; await work()) {
context.toString();
}
}
Future<void> tryPath(BuildContext context) async {
try {
await work();
} catch (_) {
context.toString();
}
}
Future<void> finallyPath(BuildContext context) async {
try {
await work();
} finally {
context.toString();
}
}
Future<void> switchUnmatched(BuildContext context, int value) async {
switch (value) {
case 1:
await work();
}
context.toString();
}
Future<void> switchGuardGap(BuildContext context, int value) async {
switch (value) {
case 1 when await ready():
context.toString();
}
}
Future<void> switchGuardFalsePath(BuildContext context, int value) async {
switch (value) {
case 1 when await ready():
break;
default:
context.toString();
}
}
Future<void> nestedInternalGap(BuildContext context) async {
Future<void> local() async {
await work();
context.toString();
}
local();
}
Future<void> classicForDoesNotReplaceOuter(BuildContext context) async {
await work();
for (int context = 0; context < 1; context++) {}
context.toString();
}
Future<void> forInContext(List<BuildContext> contexts) async {
for (final loopContext in contexts) {
await work();
loopContext.toString();
}
}
Future<void> patternForInContext(List<(BuildContext, int)> entries) async {
for (final (loopContext, _) in entries) {
await work();
loopContext.toString();
}
}
Future<void> whileBodyDoesNotReplaceOuter(BuildContext context) async {
await work();
while (false) { int context = 0; }
context.toString();
}
Future<void> doWhileBodyDoesNotReplaceOuter(BuildContext context) async {
await work();
do { int context = 0; } while (false);
context.toString();
}
Future<void> closureCapturesForInContext(List<BuildContext> contexts) async {
for (BuildContext loopContext in contexts) {
final callback = () async {
await work();
loopContext.toString();
};
callback();
}
}
Future<void> classicForContextShadow(
BuildContext context,
BuildContext other,
) async {
await work();
if (!context.mounted || !other.mounted) return;
for (BuildContext context = other; false;) {
context.toString();
}
context.toString();
}
Future<void> forInContextShadow(
BuildContext context,
List<BuildContext> contexts,
) async {
await work();
if (!context.mounted) return;
for (BuildContext context in contexts) {
context.toString();
}
context.toString();
}
Future<void> patternForInContextShadow(
BuildContext context,
List<(BuildContext, int)> entries,
) async {
await work();
if (!context.mounted) return;
for (final (BuildContext context, _) in entries) {
context.toString();
}
context.toString();
}
Future<void> whileBreakDoesNotProveMounted(BuildContext context) async {
await work();
while (!context.mounted) {
break;
}
context.toString();
}
Future<void> doBodyFactDoesNotEscape(
BuildContext context,
BuildContext other,
) async {
await work();
if (!other.mounted) return;
do {
final BuildContext context = other;
if (!context.mounted) return;
} while (false);
context.toString();
}
Future<void> conditionalBreakWhile(
BuildContext context,
bool keepGoing,
bool stop,
) async {
while (keepGoing) {
await work();
if (stop) break;
if (!context.mounted) continue;
}
context.toString();
}
Future<void> conditionalContinueFor(
BuildContext context,
bool keepGoing,
bool skip,
) async {
for (; keepGoing;) {
await work();
if (skip) continue;
if (!context.mounted) break;
}
context.toString();
}
Future<void> conditionalBreakDoWhile(
BuildContext context,
bool keepGoing,
bool stop,
) async {
do {
await work();
if (stop) break;
if (!context.mounted) continue;
} while (keepGoing);
context.toString();
}
Future<void> reassignedContext(
BuildContext context,
BuildContext other,
) async {
await work();
if (!context.mounted || !other.mounted) return;
context = other;
context.toString();
}
Future<void> inferredAssignmentContext(BuildContext context) async {
Object value = 0;
value = context;
await work();
value.toString();
}
Future<void> nestedInferredAssignmentContext(BuildContext context) async {
Object value = 0;
{
value = context;
}
await work();
value.toString();
}
Future<void> patternReassignedContext(
BuildContext context,
BuildContext other,
) async {
await work();
if (!context.mounted || !other.mounted) return;
(context, _) = (other, 0);
context.toString();
}
Future<void> outerTargetedBreak(BuildContext context, bool stop) async {
outer: while (true) {
while (true) {
if (stop) {
await work();
break outer;
}
return;
}
}
context.toString();
}
Future<void> outerTargetedContinue(
BuildContext context,
bool keepGoing,
bool skip,
) async {
outer: while (keepGoing) {
context.toString();
while (true) {
await work();
if (skip) continue outer;
return;
}
}
}
Future<void> patternDeclarationContext(BuildContext outer) async {
final (context, _) = (outer, 1);
await work();
context.toString();
}
Future<void> ifCaseContext(BuildContext outer, Object value) async {
if (value case (BuildContext context, _)) {
await work();
context.toString();
}
}
Future<void> switchPatternContext(BuildContext outer, Object value) async {
switch (value) {
case (BuildContext context, _):
await work();
context.toString();
}
}
Future<void> dynamicAssignmentPreservesContext(
BuildContext context,
dynamic value,
) async {
context = value;
await work();
context.toString();
}
Future<void> branchAssignmentKeepsContextPath(
BuildContext context,
BuildContext other,
bool clear,
) async {
var value = context;
if (clear) value = other;
await work();
value.toString();
}
Future<void> mutuallyExclusiveAssignmentStillMerges(
BuildContext context,
bool useContext,
) async {
Object value = 0;
if (useContext) {
value = context;
} else {
value = 0;
}
await work();
value.toString();
}
Future<void> caseBeforeLaterCase(BuildContext context, int value) async {
switch (value) {
case 0:
break;
case 1:
await work();
}
context.toString();
}
Future<void> caseBeforeLaterGuard(BuildContext context, int value) async {
switch (value) {
case 0:
context.toString();
break;
case 1 when await ready():
break;
}
}
Future<void> groupedCaseBeforeLaterGuard(
BuildContext context,
int value,
) async {
switch (value) {
case 0:
case 1 when await ready():
context.toString();
}
}
Future<void> chainedSwitchContinue(BuildContext context, int value) async {
switch (value) {
first:
case 0:
continue second;
second:
case 1:
await work();
continue third;
third:
default:
context.toString();
}
}
class Holder {
final BuildContext context;
Holder(this.context);
}
Future<void> propertyUse(Holder holder) async {
await work();
holder.context.toString();
}
Future<void> blockPropertyShadow(Holder holder, Holder other) async {
await work();
if (!holder.context.mounted) return;
{
final Holder holder = other;
holder.context.toString();
}
holder.context.toString();
}
Future<void> classicForPropertyShadow(Holder holder, Holder other) async {
await work();
if (!holder.context.mounted) return;
for (Holder holder = other; false;) {
holder.context.toString();
}
holder.context.toString();
}
Future<void> forInPropertyShadow(Holder holder, List<Holder> others) async {
await work();
if (!holder.context.mounted) return;
for (final holder in others) {
holder.context.toString();
}
holder.context.toString();
}
abstract class MyState extends State<StatefulWidget> {
Future<void> stateUses() async {
await work();
this.context.toString();
context!.toString();
}
Future<void> loopContextShadow(List<BuildContext> contexts) async {
await work();
if (!this.context.mounted) return;
for (BuildContext context in contexts) {
context.toString();
}
}
Future<void> parameterContextShadow(BuildContext context) async {
await work();
if (!this.context.mounted) return;
context.toString();
}
void closureContextShadow() {
final callback = (BuildContext context) async {
await work();
if (!this.context.mounted) return;
context.toString();
};
callback(this.context);
}
}
Future<void> unrelatedMountedGetter(
BuildContext context,
UnrelatedMounted receiver,
) async {
await work();
if (!receiver.mounted) return;
context.toString();
}
class UnrelatedMounted {
bool get mounted => true;
}
Future<void> whileMountedConditionIsNotGuard(BuildContext context) async {
await work();
while (context.mounted) {
context.toString();
break;
}
}
Future<void> doConditionGap(BuildContext context) async {
do {
context.toString();
} while (await ready());
}
Future<void> tryBodyGuardDoesNotEscape(BuildContext context) async {
await work();
try {
if (!context.mounted) return;
} catch (_) {}
context.toString();
}
Future<void> catchGapReachesFinally(BuildContext context) async {
try {
throw StateError('failure');
} catch (_) {
await work();
} finally {
context.toString();
}
}
Future<void> switchSubjectGap(BuildContext context) async {
switch (await ready()) {
case true:
context.toString();
case false:
break;
}
} await work(); context.toString(); await work(); if (context.mounted || consume(context) == null) {} if (context.mounted || consume(context) == null) {} if (!context.mounted && consume(context) == null) {} while (keepGoing) { context.toString(); for (; keepGoing; await work()) { context.toString(); } catch (_) { context.toString(); } finally { context.toString(); } context.toString(); case 1 when await ready(): context.toString(); default: context.toString(); await work(); context.toString(); for (int context = 0; context < 1; context++) {} context.toString(); await work(); loopContext.toString(); await work(); loopContext.toString(); while (false) { int context = 0; } context.toString(); do { int context = 0; } while (false); context.toString(); await work(); loopContext.toString(); } context.toString(); outer: while (keepGoing) { context.toString(); await work(); context.toString(); await work(); context.toString(); await work(); context.toString(); await work(); context.toString(); await work(); value.toString(); } context.toString(); case 1 when await ready(): context.toString(); await work(); holder.context.toString(); await work(); this.context.toString(); this.context.toString(); context!.toString(); if (!receiver.mounted) return; context.toString(); while (context.mounted) { context.toString(); do { context.toString(); } catch (_) {} context.toString(); } finally { context.toString();Valid
import 'package:flutter/widgets.dart';
Future<void> work() async {}
Object? consume(BuildContext context) => null;
Future<void> guarded(BuildContext context) async {
await work();
if (!context.mounted) return;
context.toString();
}
Future<void> positiveBranch(BuildContext context) async {
await work();
if (context.mounted) {
context.toString();
}
}
Future<void> guardedBooleanRhs(BuildContext context) async {
await work();
if (context.mounted && consume(context) == null) {}
if (!context.mounted || consume(context) == null) {}
}
Future<void> beforeGap(BuildContext context) async {
context.toString();
await work();
}
Future<void> matchingReceiver(BuildContext first, BuildContext second) async {
await work();
if (!first.mounted) return;
first.toString();
if (second.mounted) {
second.toString();
}
}
Future<void> irrefutableGuardFallthrough(BuildContext context, int value) async {
await work();
switch (value) {
case _ when !context.mounted:
break;
default:
context.toString();
}
}
Future<void> terminatingSwitch(BuildContext context, int value) async {
switch (value) {
case 1:
await work();
return;
default:
break;
}
context.toString();
}
Future<void> outerGapDoesNotEnterClosure(BuildContext context) async {
await work();
final callback = () {
context.toString();
};
callback();
}
Future<void> targetedContinue(BuildContext context, bool keepGoing) async {
outer: while (keepGoing) {
if (context.mounted) continue outer;
break outer;
}
}
Future<void> forInShadowsContext(BuildContext context) async {
await work();
for (int context in <int>[1]) {
context.toString();
}
}
Future<void> patternForInShadowsContext(BuildContext context) async {
await work();
for (final (int context, _) in <(int, int)>[(1, 2)]) {
context.toString();
}
}
Future<void> guardedOuterSurvivesClassicFor(BuildContext context) async {
await work();
if (!context.mounted) return;
for (int context = 0; context < 1; context++) {
context.toString();
}
context.toString();
}
Future<void> classicForMountedCondition(BuildContext context) async {
await work();
for (; context.mounted;) {
context.toString();
break;
}
}
Future<void> doWhileMountedExit(BuildContext context) async {
await work();
do {} while (!context.mounted);
context.toString();
}
Future<void> guardedGapBranch(BuildContext context, bool flag) async {
if (flag) {
await work();
if (!context.mounted) return;
}
context.toString();
}
Future<void> repeatedWhileGuard(BuildContext context, bool keepGoing) async {
await work();
while (keepGoing) {
if (!context.mounted) return;
context.toString();
}
}
Future<void> repeatedClassicForGuard(
BuildContext context,
bool keepGoing,
) async {
await work();
for (; keepGoing;) {
if (!context.mounted) return;
context.toString();
}
}
Future<void> repeatedDoWhileGuard(BuildContext context, bool keepGoing) async {
await work();
do {
if (!context.mounted) return;
context.toString();
} while (keepGoing);
}
Future<void> unreachableAfterConditionlessFor(BuildContext context) async {
for (;;) {
await work();
}
context.toString();
}
Future<void> multiDeclaratorShadow(BuildContext context) async {
await work();
{
var context = 0, value = context.toString();
value.toString();
}
}
Future<void> unbracedIfScope(
BuildContext context,
BuildContext other,
bool replace,
) async {
await work();
if (!context.mounted) return;
if (replace) { int context = 0; }
context.toString();
}
Future<void> tryCatchFinallyScopes(
BuildContext context,
BuildContext other,
) async {
await work();
if (!context.mounted) return;
try {
final int context = 0;
context.toString();
} on Object catch (context, stackTrace) {
context.toString();
stackTrace.toString();
} finally {
final int context = 0;
context.toString();
}
context.toString();
}
Future<void> nonContextIfCaseShadow(BuildContext context, Object value) async {
await work();
if (value case (int context, _)) {
context.toString();
}
}
Future<void> nonContextSwitchShadow(BuildContext context, Object value) async {
await work();
switch (value) {
case (int context, _):
context.toString();
}
}
Future<void> unreachableAfterReturningSwitch(
BuildContext context,
int value,
) async {
await work();
switch (value) {
case 0:
return;
default:
return;
}
context.toString();
}
Future<void> returningAssignmentDoesNotLeak(
BuildContext context,
bool replace,
) async {
Object value = 0;
if (replace) {
value = context;
return;
}
await work();
value.toString();
}
Future<void> mutuallyExclusiveAssignment(
BuildContext context,
bool useContext,
) async {
Object value = 0;
if (useContext) {
value = context;
} else {
await work();
value.toString();
}
}
abstract class MyState extends State<StatefulWidget> {
Future<void> guardedState() async {
await work();
if (!mounted) return;
context.toString();
this.context.toString();
}
Future<void> nonContextLoopShadow() async {
await work();
for (int context in <int>[1]) {
context.toString();
}
}
void localFunctionContextShadow() {
Future<void> context() async {
await work();
context();
}
context();
}
void nonContextClosureShadow() {
final callback = (int context) async {
await work();
context.toString();
};
callback(1);
}
void unbracedIfLocalFunctionShadow(bool enabled) {
if (enabled)
Future<void> context() async {
await work();
context();
}
}
void unbracedLoopLocalFunctionShadow() {
while (false)
Future<void> context() async {
await work();
context();
}
}
void labeledLocalFunctionShadow() {
declaration:
Future<void> context() async {
await work();
context();
}
}
}
// The official rule matches the mounted getter, not receiver identity.
Future<void> otherContextMountedGetter(
BuildContext context,
BuildContext other,
) async {
await work();
if (other.mounted) {
context.toString();
}
}
Future<void> declaredObjectDoesNotBecomeContext(BuildContext context) async {
Object value = context;
await work();
value.toString();
}
Future<void> declaredDynamicDoesNotBecomeContext(BuildContext context) async {
dynamic value = 0;
value = context;
await work();
value.toString();
}
Future<void> finallyGuardEscapes(BuildContext context) async {
try {
await work();
} finally {
if (!context.mounted) return;
}
context.toString();
}
Future<void> catchGuardAppliesInsideCatch(BuildContext context) async {
try {
await work();
} catch (_) {
if (!context.mounted) return;
context.toString();
}
}
Future<void> switchMountedWhenGuard(BuildContext context, int value) async {
await work();
switch (value) {
case 0 when context.mounted:
context.toString();
default:
break;
}
}
Future<void> doBodyGapIsObserved(BuildContext context) async {
do {
context.toString();
await work();
} while (false);
}
abstract class OtherMountedState extends State<StatefulWidget> {
Future<void> otherStateGetterGuardsStateContext(
State<StatefulWidget> other,
) async {
await work();
if (!other.mounted) return;
context.toString();
}
}
Future<void> infiniteLoopMountedExit(BuildContext context) async {
await work();
if (!context.mounted) {
while (true) {}
}
context.toString();
}
Never stop() => throw StateError('stopped');
Future<void> neverCallMountedExit(BuildContext context) async {
await work();
if (!context.mounted) stop();
context.toString();
}Configure use-build-context-synchronously
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"use-build-context-synchronously": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/use-build-context-synchronously: <reason>More correctness rules
- use-closest-build-contextrecommendedflutter
Use the nearest
BuildContextparameter inside nested callbacks. - use-key-in-widget-constructors
use_key_in_widget_constructorsrecommendedflutterRequire public widget constructors to accept or initialize a Flutter
Key. - use-once-constructors-once-provider
use_once_constructors_once_providerflutterRequire Riverpod once-providers to be created through
.once(). - use-ref-and-state-synchronouslyrecommendedriverpod
Flags notifier ref and state accesses after an async gap without ref.mounted.
- use-ref-read-synchronouslyrecommendedriverpod
Flags Riverpod WidgetRef.read calls after an async gap without a mounted guard.
- use-setstate-synchronouslyrecommendedflutter
Require a mounted check before calling setState after an async gap.
- valid-regexps
valid_regexpsrecommendedDisallow statically known invalid
dart:coreregular expressions. - void-checks
void_checksrecommendedDon't pass or assign values to
void(orFutureOr<void>) locations.