dispose-focus-node-and-timer
- Group
- Correctness
- Path
lint/correctness/dispose-focus-node-and-timer- Default
- On (recommended)
- Origin
- Falcon
- Domain
- flutter
- Rule
- 222 of 512
Requires owned FocusNode and Timer fields to be released in State.dispose().
Only fields constructed by a resolved Flutter FocusNode or dart:async Timer
constructor are checked, including assignments in lifecycle methods. A direct
dispose()/cancel() invocation in dispose() is required; tear-offs, callbacks,
and conditional-only invocations do not prove release. Borrowed and static
fields are ignored. Controllers belong to proper-controller-dispose; other
disposable fields belong to dispose-fields, and unretained temporary objects
belong to avoid-undisposed-instances.
Calls after a possible return/throw are not proof, including idempotence
guards whose cross-invocation state is outside this rule's analysis.
Invalid
import 'dart:async';
import 'package:flutter/material.dart';
class A extends State<StatefulWidget> {
final focus = FocusNode();
final timer = Timer(Duration.zero, () {});
final periodic = Timer.periodic(Duration.zero, (_) {});
final tearoff = FocusNode();
final closure = FocusNode();
final conditional = FocusNode();
void dispose() {
tearoff.dispose;
final callback = () => closure.dispose();
if (false) conditional.dispose();
super.dispose();
}
}
class EarlyReturn extends State<StatefulWidget> {
final focus = FocusNode();
final timer = Timer(Duration.zero, () {});
void dispose() {
if (mounted) return;
focus.dispose();
timer.cancel();
super.dispose();
}
}
class ThrowExpression extends State<StatefulWidget> {
final focus = FocusNode();
void dispose() {
final check = mounted ? null : throw StateError('not mounted');
focus.dispose();
super.dispose();
}
}class A extends State<StatefulWidget> { final focus = FocusNode(); final focus = FocusNode(); final timer = Timer(Duration.zero, () {}); final timer = Timer(Duration.zero, () {}); final periodic = Timer.periodic(Duration.zero, (_) {}); final periodic = Timer.periodic(Duration.zero, (_) {}); final tearoff = FocusNode(); final tearoff = FocusNode(); final closure = FocusNode(); final closure = FocusNode(); final conditional = FocusNode();class EarlyReturn extends State<StatefulWidget> { final focus = FocusNode(); final focus = FocusNode(); final timer = Timer(Duration.zero, () {});class ThrowExpression extends State<StatefulWidget> { final focus = FocusNode();Valid
import 'dart:async';
import 'package:flutter/material.dart';
class A extends State<StatefulWidget> {
final focus = FocusNode();
final timer = Timer(Duration.zero, () {});
final periodic = Timer.periodic(Duration.zero, (_) {});
final controller = TextEditingController();
static final shared = FocusNode();
FocusNode? borrowed;
void dispose() {
focus.dispose();
timer.cancel();
periodic.cancel();
controller.dispose();
super.dispose();
}
}
class Other { final focus = FocusNode(); }
class Arrow extends State<StatefulWidget> {
final focus = FocusNode();
void dispose() => focus.dispose();
}
class OrderIndependent extends State<StatefulWidget> {
Timer? timer;
FocusNode? focus = FocusNode();
void dispose() {
timer!.cancel();
focus!.dispose();
super.dispose();
}
void start() { timer = Timer.periodic(Duration.zero, (_) {}); }
}
class NestedReturn extends State<StatefulWidget> {
final focus = FocusNode();
void dispose() {
void nested() { return; }
focus.dispose();
super.dispose();
}
}Configure dispose-focus-node-and-timer
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"dispose-focus-node-and-timer": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/dispose-focus-node-and-timer: <reason>More correctness rules
- dispose-provided-instancesrecommendedriverpod
Flags provider-created instances with a dispose method that lack ref.onDispose cleanup.
- dispose-provider-resourcesrecommendedriverpod
Flags provider-created resources without autoDispose or ref.onDispose cleanup.
- dispose-providersrecommendedprovider
Requires cleanup callbacks for disposable values created by package:provider's Provider.
- emit-new-bloc-state-instancesrecommendedbloc
Flags Bloc and Cubit emissions that reuse their current state instance.
- exhaustive-cases
exhaustive_casesrecommendedRequire switch statements over enum-like classes to cover every constant value.
- function-always-returns-null
Flags value functions with a proven explicit null return on every path.
- function-always-returns-same-value
Warns when distinct return paths in a function produce the same scalar constant.
- handle-bloc-event-subclassesbloc
Warns when a Bloc constructor leaves a concrete event subclass without a handler.