dispose-providers

Path
lint/correctness/dispose-providers
Default
On (recommended)
Origin
Falcon
Domain
provider
Rule
225 of 512
recommendedprovider

Requires cleanup callbacks for disposable values created by package:provider's Provider.

The created value's inferred type must declare or inherit an instance method named dispose, close, or cancel. Each such method must be called on the dispose callback's value parameter, not another object or a shadowing local. Value constructors do not own their values. Creation is proven only for direct generative constructors or simple same-file function tear-offs returning one. Unknown factories, non-inline cleanup, and path-sensitive guarantees are outside this rule's scope.

Invalid

example.dartdart
import 'package:provider/provider.dart' as p;

class Disposable {
  void dispose() {}
}

class Closable {
  void close() {}
}

class Cancelable {
  void cancel() {}
}

class InheritedDisposable extends Disposable {}

final other = Disposable();
Disposable makeDisposable(dynamic context) => Disposable();

void examples() {
  p.Provider(create: (_) => Disposable());
  p.Provider(create: (_) => Closable());
  p.Provider(create: (_) => Cancelable());
  p.Provider(create: makeDisposable);
  p.Provider(create: (_) { return Disposable(); });
  new p.Provider(create: (_) => InheritedDisposable());
  p.Provider(create: (_) => Disposable(), dispose: (_, value) {});
  p.Provider(create: (_) => Disposable(), dispose: (_, value) => other.dispose());
  p.Provider(create: (_) => Disposable(), dispose: (_, value) => value.toString());
  p.Provider(create: (_) => Disposable(), dispose: (_, value) {
    void later() { value.dispose(); }
  });
  p.Provider(create: (_) => Disposable(), dispose: (_, value) {
    { final value = other; value.dispose(); }
  });
}
Dispose the created value in this `Provider`'s `dispose` callback.
20void examples() {
21 p.Provider(create: (_) => Disposable());
Dispose the created value in this `Provider`'s `dispose` callback.
21 p.Provider(create: (_) => Disposable());
22 p.Provider(create: (_) => Closable());
Dispose the created value in this `Provider`'s `dispose` callback.
22 p.Provider(create: (_) => Closable());
23 p.Provider(create: (_) => Cancelable());
Dispose the created value in this `Provider`'s `dispose` callback.
23 p.Provider(create: (_) => Cancelable());
24 p.Provider(create: makeDisposable);
Dispose the created value in this `Provider`'s `dispose` callback.
24 p.Provider(create: makeDisposable);
25 p.Provider(create: (_) { return Disposable(); });
Dispose the created value in this `Provider`'s `dispose` callback.
25 p.Provider(create: (_) { return Disposable(); });
26 new p.Provider(create: (_) => InheritedDisposable());
Dispose the created value in this `Provider`'s `dispose` callback.
26 new p.Provider(create: (_) => InheritedDisposable());
27 p.Provider(create: (_) => Disposable(), dispose: (_, value) {});
Dispose the created value in this `Provider`'s `dispose` callback.
27 p.Provider(create: (_) => Disposable(), dispose: (_, value) {});
28 p.Provider(create: (_) => Disposable(), dispose: (_, value) => other.dispose());
Dispose the created value in this `Provider`'s `dispose` callback.
28 p.Provider(create: (_) => Disposable(), dispose: (_, value) => other.dispose());
29 p.Provider(create: (_) => Disposable(), dispose: (_, value) => value.toString());
Dispose the created value in this `Provider`'s `dispose` callback.
29 p.Provider(create: (_) => Disposable(), dispose: (_, value) => value.toString());
30 p.Provider(create: (_) => Disposable(), dispose: (_, value) {
Dispose the created value in this `Provider`'s `dispose` callback.
32 });
33 p.Provider(create: (_) => Disposable(), dispose: (_, value) {

Valid

example.dartdart
import 'package:provider/provider.dart' as p;

class Disposable {
  void dispose() {}
}

class Closable {
  void close() {}
}

class Cancelable {
  void cancel() {}
}

class InheritedDisposable extends Disposable {}
class Plain {}
Disposable makeDisposable(dynamic context) => Disposable();

class StaticCleanup { static void dispose() {} }

final shared = Disposable();
T getIt<T>() => shared as T;
class Api extends Disposable {
  Api();
  factory Api.cached() => singleton;
  static final singleton = Api();
  static Api instance() => singleton;
}

// A local constructor with the same spelling is not a package provider.
class Provider {
  Provider({required Object Function(Object?) create});
}

void examples() {
  p.Provider(create: (_) => Disposable(), dispose: (_, value) => value.dispose());
  p.Provider(create: (_) => Closable(), dispose: (_, value) { value.close(); });
  p.Provider(create: (_) => Cancelable(), dispose: (_, value) => value.cancel());
  new p.Provider(create: (_) => InheritedDisposable(), dispose: (_, value) => value.dispose());
  p.Provider(create: (_) => Disposable(), dispose: (_, value) => value..dispose());
  p.Provider.value(value: Disposable());
  p.Provider(create: makeDisposable, dispose: (_, value) => value.dispose());
  p.Provider(create: (_) { return Disposable(); }, dispose: (_, value) { value.dispose(); });
  p.Provider(create: (_) => Plain());
  p.Provider(create: (_) => StaticCleanup());
  Provider(create: (_) => Disposable());
  p.Provider(create: (_) => Disposable(), dispose: (_, value) => value!.dispose());
  p.Provider(create: (_) => Disposable(), dispose: (_, value) => (value as Disposable).dispose());
  final existing = Disposable();
  p.Provider(create: (_) => existing);
  p.Provider(create: (dynamic context) => context.read<Disposable>());
  p.Provider(create: (_) => getIt<Disposable>());
  p.Provider(create: (_) => Api.instance());
  p.Provider(create: (_) => Api.cached());
}

Configure dispose-providers

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "dispose-providers": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/correctness/dispose-providers: <reason>