implicit-reopen

Same as implicit_reopen in Dart lints

Path
lint/correctness/implicit-reopen
Default
Off, opt in
Origin
Dart lints
Rule
245 of 512

Flags classes that implicitly reopen a supertype declared in the same library.

Class modifiers are only enforced across library boundaries, so inside its own library an interface or final class can be extended by a class that drops the restriction — silently letting other libraries extend what the author meant to close. Mark the subclass with the same modifier, or annotate it with package:meta's @reopen when reopening is intended.

interface class I {}
class C extends I {}          // flagged: reopens 'I' (not marked 'interface')

final class F {}
base class B extends F {}     // flagged: reopens 'F' (not marked 'final')

Sealed and mixin classes and classes annotated with @reopen are exempt. Only superclasses declared in the same library (this file or its parts) are considered, including named mixin applications. A sealed superclass carries the modifier its own supertypes induce (a sealed subclass of an interface class is an interface).

Invalid

example.dartdart
interface class I {}

class C extends I {}

abstract class D extends I {}

base class B extends I {}

final class F {}

base class G extends F {}

mixin M {}

class Alias = I with M;

base class BaseAlias = F with M;

// Sealed intermediates retain restrictions induced by their superclass.
sealed class SealedInterface extends I {}

class ReopensInterface extends SealedInterface {}

sealed class SealedFinal extends F {}

base class ReopensFinal extends SealedFinal {}

// A named mixin application is still a class and induces restrictions.
mixin EmptyMixin {}
sealed class SealedAlias = I with EmptyMixin;

class ReopensAlias extends SealedAlias {}

sealed class SealedFinalAlias = F with EmptyMixin;

base class ReopensFinalAlias extends SealedFinalAlias {}
The class `C` reopens `I` because it is not marked `interface`.
2
3class C extends I {}
The class `D` reopens `I` because it is not marked `interface`.
4
5abstract class D extends I {}
The class `B` reopens `I` because it is not marked `interface`.
6
7base class B extends I {}
The class `G` reopens `F` because it is not marked `final`.
10
11base class G extends F {}
The class `Alias` reopens `I` because it is not marked `interface`.
14
15class Alias = I with M;
The class `BaseAlias` reopens `F` because it is not marked `final`.
16
17base class BaseAlias = F with M;
The class `ReopensInterface` reopens `SealedInterface` because it is not marked `interface`.
21
22class ReopensInterface extends SealedInterface {}
The class `ReopensFinal` reopens `SealedFinal` because it is not marked `final`.
25
26base class ReopensFinal extends SealedFinal {}
The class `ReopensAlias` reopens `SealedAlias` because it is not marked `interface`.
31
32class ReopensAlias extends SealedAlias {}
The class `ReopensFinalAlias` reopens `SealedFinalAlias` because it is not marked `final`.
35
36base class ReopensFinalAlias extends SealedFinalAlias {}

Valid

example.dartdart
import 'package:meta/meta.dart';

interface class I {}

interface class C extends I {}

final class E extends I {}

sealed class S extends I {}

@reopen
class R extends I {}

final class F {}

final class G extends F {}

sealed class H extends F {}

base class Open {}

base class Plain extends Open {}

// Supertype from another library.
class Remote extends SomeUnknownBase {}

class Base {}

class Derived extends Base {}

sealed class SealedInterface extends I {}

interface class KeepsInterface extends SealedInterface {}

sealed class SealedFinal extends F {}

final class KeepsFinal extends SealedFinal {}

mixin EmptyMixin {}
sealed class SealedAlias = I with EmptyMixin;

interface class KeepsAliasInterface extends SealedAlias {}

Configure implicit-reopen

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "implicit-reopen": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/correctness/implicit-reopen: <reason>