use-late-for-private-fields-and-variables

Same as use_late_for_private_fields_and_variables in Dart lints

Group
Style
Path
lint/style/use-late-for-private-fields-and-variables
Default
Off, opt in
Origin
Dart lints
Rule
495 of 512

Flags a private nullable field or top-level variable that is only ever assigned non-null values and read through !, so it could be late with a non-nullable type.

When every read of a private variable is a null assertion and every write stores a non-nullable value, the nullable type only exists to defer initialization; late expresses that and moves the null check into the runtime. Candidates are private (underscore) top-level variables and private fields (instance or static), plus every field of a private extension; instance fields of extension types, fields of classes with a const constructor, and all enum members are skipped, as are late, const, external, and abstract declarations. Any other use — a plain read, a this._x initializing formal, a : _x = ... initializer, a compound or ??= assignment, or an assignment whose value is not proven non-nullable — disqualifies the referenced declaration. Qualified and cascade accesses are attributed to their resolved declaration, not every implementation of an interface member. Uses in every resolved library part are checked together; unresolved parts prevent proving a candidate safe.

int? _i; // flagged
void f() {
  _i = 1;
  print(_i!);
}

Invalid

example.dartdart
int? _i;

String? _name;

void setUp() {
  _i = 1;
  _name = 'falcon';
}

void use() {
  print(_i!);
  print(_name!.length);
}

class Cache {
  List<int>? _items;
  static String? _label;
  Object? _value = Object();

  void init() {
    _items = [1, 2, 3];
    _label = 'cache';
  }

  int get first => _items!.first;
  String get label => _label!;
  Object get value => _value!;
}

class Counter {
  int? _count;

  void reset() {
    this._count = 0;
  }

  int next() => _count! + 1;
}

// Each class's field is its own declaration: a plain read of the other
// class's same-named field does not disqualify this one.
class NullAsserted {
  int? _count;

  int next() => _count! + 1;
}

// A read inside a class with a const constructor is not visited.
class ConstReader {
  const ConstReader();
  int? read() => _i;
}

// Writes through a type name keep the field lateable.
class Qualified {
  static int? _shared;

  static int read() => _shared!;
}

void initShared() {
  Qualified._shared = 1;
}

extension _Helpers on String {
  static int? cached;

  int get size {
    cached = 3;
    return cached!;
  }
}
Use `late` for private members with a non-nullable type.
1int? _i;
Use `late` for private members with a non-nullable type.
2
3String? _name;
Use `late` for private members with a non-nullable type.
15class Cache {
16 List<int>? _items;
Use `late` for private members with a non-nullable type.
16 List<int>? _items;
17 static String? _label;
Use `late` for private members with a non-nullable type.
17 static String? _label;
18 Object? _value = Object();
Use `late` for private members with a non-nullable type.
30class Counter {
31 int? _count;
Use `late` for private members with a non-nullable type.
42class NullAsserted {
43 int? _count;
Use `late` for private members with a non-nullable type.
55class Qualified {
56 static int? _shared;
Use `late` for private members with a non-nullable type.
65extension _Helpers on String {
66 static int? cached;

Valid

example.dartdart
late int _lateInt;

int? publicNullable;

int? _readPlain;

int? _assignedNull;

int _nonNullable = 0;

void use() {
  _lateInt = 1;
  print(_lateInt);
  publicNullable = 1;
  print(publicNullable!);
  print(_readPlain);
  _assignedNull = null;
  print(_assignedNull!);
  _nonNullable = 2;
  print(_nonNullable);
}

int? _compound;

void bump() {
  _compound ??= 1;
  print(_compound!);
}

class Holder {
  int? _initialized;
  int? _publicRead;
  int? _nullableWrite;

  Holder(this._initialized);

  int get value => _initialized!;
  int? get raw => _publicRead;

  void write(int? next) {
    _nullableWrite = next;
    print(_nullableWrite!);
  }
}

class ConstHolder {
  final int? _value;
  const ConstHolder(this._value);
  int get value => _value!;
}

enum Mode {
  a;

  static int? _cached;
  static int get cached => _cached!;
}

class Initialized {
  String? _name;
  Initialized() : _name = 'x';
  String get name => _name!;
}

// Through `this.` or another receiver, the analyzer also visits the bare
// property name, which counts as a nullable read even under `!`.
class ThisAsserted {
  int? _count;

  void reset() {
    this._count = 0;
  }

  int next() => this._count! + 1;
}

class PlainReader {
  int? _count;

  void reset() {
    _count = 0;
  }

  int? peek(PlainReader other) => other._count;
}

class Shadowed {
  int? _total;

  void reset() {
    _total = 0;
  }

  int? read() => _total;
}

// `Type._x!` is a prefixed identifier: its bare name is a nullable read.
class QualifiedRead {
  static int? _shared;

  static void init() {
    _shared = 1;
  }
}

int sharedValue() => QualifiedRead._shared! + 1;

Configure use-late-for-private-fields-and-variables

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "use-late-for-private-fields-and-variables": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/style/use-late-for-private-fields-and-variables: <reason>
  • use-named-constantsuse_named_constantsrecommended

    Prefers a class's predefined static constant to constructing an equal constant.

  • use-raw-stringsuse_raw_strings

    Flags string literals whose only escapes are \\ and \$, which a raw string would express without any backslash.

  • use-setters-to-change-propertiesuse_setters_to_change_properties

    Flags one-parameter void methods that only assign that parameter to a field.

  • use-spacer-as-expanded-childuse_spacer_as_expanded_childrecommendedflutter

    Flags an Expanded wrapping an empty SizedBox or Container that should be a Spacer.

  • use-string-in-part-of-directivesuse_string_in_part_of_directivesrecommended

    Flags a part of directive that names its library instead of using a string URI.

  • use-super-parametersuse_super_parametersrecommended

    Prefer super parameters when a constructor only forwards parameters to its superclass.

  • use-test-throws-matchersuse_test_throws_matchersrecommended

    Prefers throwsA matchers over try { ...; fail(...); } catch (...) {}.

  • use-to-and-as-if-applicableuse_to_and_as_if_applicable

    Flags conversion methods not named to… or as….