correct-order-for-super-dispose

Same as correct_order_for_super_dispose in Pyramid Lint

Path
lint/correctness/correct-order-for-super-dispose
Default
On (recommended)
Origin
Pyramid Lint
Domain
flutter
Rule
211 of 512
recommendedflutter

Require super.dispose() to be the last call in dispose.

Flags a super.dispose() invocation that is not the final statement of a dispose method. The base State.dispose tears down the framework's own bookkeeping for the object, after which touching the widget's fields is unsafe, so any cleanup your subclass performs must happen first. A super.dispose() in the middle of the method leaves the remaining cleanup running against a half-disposed object. Move the super.dispose() call to the end. Checks direct statements of method block bodies, not nested blocks, callbacks, or other declarations named dispose.

Invalid

example.dartdart
import 'package:flutter/material.dart';

/// Calling super.dispose before cleanup
class BadDisposeOrder extends ChangeNotifier {
  late AnimationController controller;
  late StreamSubscription subscription;

  @override
  void dispose() {
    super.dispose();
    controller.dispose();
    subscription.cancel();
  }
}

/// Another bad example
class AnotherBadDispose extends ChangeNotifier {
  late TextEditingController textController;
  late FocusNode focusNode;

  @override
  void dispose() {
    super.dispose();
    textController.dispose();
    focusNode.dispose();
  }
}

/// Multiple resources with super called first
class MultipleResourceDispose extends ChangeNotifier {
  late StreamController streamController;
  late Timer timer;

  @override
  void dispose() {
    super.dispose();
    streamController.close();
    timer.cancel();
  }
}

/// Bad: super.dispose in middle
class MiddleDispose extends ChangeNotifier {
  late ScrollController scrollController;

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
    print('cleanup done');
  }
}

/// Bad: early super call with multiple cleanups
class EarlySuper extends ChangeNotifier {
  late PageController pageController;
  late TabController tabController;

  @override
  void dispose() {
    super.dispose();
    pageController.dispose();
    tabController.dispose();
  }
}
Call `super.dispose()` last in the `dispose` method.
9 void dispose() {
10 super.dispose();
Call `super.dispose()` last in the `dispose` method.
22 void dispose() {
23 super.dispose();
Call `super.dispose()` last in the `dispose` method.
35 void dispose() {
36 super.dispose();
Call `super.dispose()` last in the `dispose` method.
48 scrollController.dispose();
49 super.dispose();
Call `super.dispose()` last in the `dispose` method.
60 void dispose() {
61 super.dispose();

Valid

example.dartdart
import 'package:flutter/material.dart';

/// Cleanup before calling super.dispose
class GoodDisposeOrder extends ChangeNotifier {
  late AnimationController controller;
  late StreamSubscription subscription;

  @override
  void dispose() {
    controller.dispose();
    subscription.cancel();
    super.dispose();
  }
}

/// Another good example
class AnotherGoodDispose extends ChangeNotifier {
  late TextEditingController textController;
  late FocusNode focusNode;

  @override
  void dispose() {
    textController.dispose();
    focusNode.dispose();
    super.dispose();
  }
}

/// Multiple resources with correct order
class MultipleResourceDispose extends ChangeNotifier {
  late StreamController streamController;
  late Timer timer;

  @override
  void dispose() {
    streamController.close();
    timer.cancel();
    super.dispose();
  }
}

/// Single resource cleanup
class SingleResourceDispose extends ChangeNotifier {
  late AnimationController animation;

  @override
  void dispose() {
    animation.dispose();
    super.dispose();
  }
}

/// Good: cleanup with super at end
class ScrollDispose extends ChangeNotifier {
  late ScrollController scrollController;

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }
}

/// Good: multiple cleanup steps then super
class ComplexDispose extends ChangeNotifier {
  late PageController pageController;
  late TabController tabController;
  late StreamSubscription streamSub;

  @override
  void dispose() {
    pageController.dispose();
    tabController.dispose();
    streamSub.cancel();
    super.dispose();
  }
}

Configure correct-order-for-super-dispose

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "correct-order-for-super-dispose": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/correctness/correct-order-for-super-dispose: <reason>