proper_super_calls
Warns when super lifecycle methods are called in the wrong order in State subclasses. Methods like initState, didUpdateWidget, activate, didChangeDependencies, and reassemble must call super first. Methods like deactivate and dispose must call super last.
Why use this rule
Section titled “Why use this rule”Flutter’s State lifecycle splits into two halves, and super goes on opposite ends of each:
superfirst —initState,didChangeDependencies,didUpdateWidget,activate,reassemble. The framework sets up its own state before yours reads it.superlast —deactivate,dispose. Your cleanup runs while the framework’s state is still there to clean up against.
Getting it backwards is not always visible immediately: super.dispose() first tears down the element, and a controller disposed after it may throw only under a particular navigation. The quick fix moves the call to the right end.
See also: State.initState | State.dispose
super.initState() after your own setup:
class _EditorState extends State<Editor> { late final TextEditingController _controller;
@override void initState() { _controller = TextEditingController(text: widget.initialText); super.initState(); }
@override Widget build(BuildContext context) => const SizedBox();}super.dispose() before your cleanup:
class _EditorState extends State<Editor> { late final TextEditingController _controller;
@override void dispose() { super.dispose(); _controller.dispose(); }
@override Widget build(BuildContext context) => const SizedBox();}deactivate follows dispose — super goes last there too:
class _EditorState extends State<Editor> { @override void deactivate() { super.deactivate(); _unsubscribeFromDocument(); }
@override Widget build(BuildContext context) => const SizedBox();}class _EditorState extends State<Editor> { late final TextEditingController _controller;
@override void initState() { super.initState(); _controller = TextEditingController(text: widget.initialText); }
@override void deactivate() { _unsubscribeFromDocument(); super.deactivate(); }
@override void dispose() { _controller.dispose(); super.dispose(); }
@override Widget build(BuildContext context) => const SizedBox();}Known limitations
Section titled “Known limitations”A method with no super call at all is not reported — whether the override is
allowed to skip super is a different question, and this rule only orders a
call that is already there.
Only subclasses of Flutter’s State are checked, unless state_base_classes
names another base class.
Turning this rule off
Section titled “Turning this rule off”This rule is in the recommended preset, so it is on with
preset: recommended or preset: opinionated. Add it to preset: core with
proper_super_calls: true.
To turn it off:
rules: proper_super_calls: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”state_base_classes
Section titled “state_base_classes”An intermediate base class that itself extends State needs no configuration —
the check walks the hierarchy. This option is for the other case: a state-like
base class that does not extend Flutter’s State at all, which the rule
would otherwise skip entirely.
many_lints: rules: proper_super_calls: state_base_classes: [TrackedState]rules: proper_super_calls: state_base_classes: [TrackedState]// Not a Flutter State — its own lifecycle, same ordering contract.abstract class TrackedState { void initState() {}
void dispose() {}}
class ReportPresenter extends TrackedState { late final Stream<int> _updates;
@override void initState() { _updates = const Stream.empty(); super.initState(); // LINT — super must come first }}| Option | Type | Default | Description |
|---|---|---|---|
state_base_classes |
list of strings | [] |
Additional non-State base classes whose subclasses should be treated as state classes |
Related rules
Section titled “Related rules”avoid_cascade_after_if_null— Detect cascades after if-null operators without parentheses.avoid_collapsible_if— Merge nested if statements with &&.avoid_constant_conditions— Detect comparisons where both sides are constants.avoid_constant_switches— Detect switch statements on constant expressions.