Skip to content

proper_super_calls

v0.4.0 Warning Fix Control Flow

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.

Flutter’s State lifecycle methods have a specific contract about when super should be called. Calling super.initState() after your own initialization code can lead to errors because the framework expects to set up its own state first. Conversely, calling super.dispose() before your cleanup code means your resources are released while the framework has already torn down its own state. The quick fix automatically moves the super call to the correct position.

See also: State.initState | State.dispose

class _BadInitStateState extends State<BadInitState> {
String _data = '';
@override
void initState() {
_data = 'Hello'; // super.initState() should come before this
super.initState();
}
@override
Widget build(BuildContext context) => const SizedBox();
}
class _BadDisposeState extends State<BadDispose> {
@override
void dispose() {
super.dispose(); // super.dispose() should come after cleanup
debugPrint('cleanup');
}
@override
Widget build(BuildContext context) => const SizedBox();
}
class _BadDeactivateState extends State<BadDeactivate> {
@override
void deactivate() {
super.deactivate(); // super.deactivate() should come after cleanup
debugPrint('deactivating');
}
@override
Widget build(BuildContext context) => const SizedBox();
}
class _GoodInitStateState extends State<GoodInitState> {
String _data = '';
@override
void initState() {
super.initState(); // First
_data = 'Hello';
}
@override
Widget build(BuildContext context) => const SizedBox();
}
class _GoodDisposeState extends State<GoodDispose> {
@override
void dispose() {
debugPrint('cleanup');
super.dispose(); // Last
}
@override
Widget build(BuildContext context) => const SizedBox();
}
class _GoodDeactivateState extends State<GoodDeactivate> {
@override
void deactivate() {
debugPrint('deactivating');
super.deactivate(); // Last
}
@override
Widget build(BuildContext context) => const SizedBox();
}

To disable this rule:

plugins:
many_lints:
diagnostics:
proper_super_calls: false