diagnostic-describe-all-properties

Same as diagnostic_describe_all_properties in Dart lints

Path
lint/correctness/diagnostic-describe-all-properties
Default
Off, opt in
Origin
Dart lints
Domain
flutter
Rule
218 of 512
flutter

Requires every public property of a Diagnosticable class to be referenced in its debug methods.

Flutter's diagnostics (the widget inspector, debugDumpApp, toString) only show what debugFillProperties adds, so a public field or getter that is never mentioned there — nor in debugDescribeChildren — is invisible when debugging. A property counts as described when its name, or its debug-prefixed variant (debugFoo for foo), appears as an identifier in either method. Widget-valued properties (and List/Set of widgets) are exempt because they are described as children, and so are static members, private members, and overrides (a field or getter does not override an inherited setter). Like the analyzer, the rule applies to classes with a supertype named Diagnosticable declared in an unnamed library, including dependency libraries. Declared and inferred property types are checked; unresolved types stay silent. Declaring primary constructor parameters are checked like instance fields.

class Tile extends StatelessWidget {
  final String title; // BAD: not described

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
  }
}

Invalid

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

class Tile extends StatelessWidget {
  const Tile({
    super.key,
    required this.title,
    required this.count,
    required this.tags,
    required this.child,
  });

  final String title;
  final int count;
  final List<String> tags;
  final Widget child;

  bool get enabled => count > 0;

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('count', count));
  }

  @override
  Widget build(BuildContext context) => child;
}

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int clicks = 0;
  DateTime? lastClick;

  @override
  Widget build(BuildContext context) => const Placeholder();
}

class Model with Diagnosticable {
  Model(this.value);

  final double value;
  final Duration timeout = Duration.zero;
}

class Choice<T> extends StatelessWidget {
  const Choice({super.key, required this.value});

  final T value;

  @override
  Widget build(BuildContext context) => const SizedBox();
}

abstract class SinkWidget extends StatelessWidget {
  const SinkWidget({super.key});

  set sink(int value);
}

class Sink extends SinkWidget {
  Sink({super.key});

  // A field does not override an inherited setter.
  int sink = 0;

  @override
  Widget build(BuildContext context) => const SizedBox();
}

class InferredModel with Diagnosticable {
  final count = 1;
  final values = <String>[];
}

class DebugScopeModel with Diagnosticable {
  final int outsideBody = 1;
  final int nestedReference = 2;

  void otherMethod() {
    print(outsideBody);
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    final deferred = () => nestedReference;
    properties.add(IntProperty('nestedReference', deferred()));
  }
}
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
12
13 final String title;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
14 final int count;
15 final List<String> tags;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
17
18 bool get enabled => count > 0;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
37class _CounterState extends State<Counter> {
38 int clicks = 0;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
38 int clicks = 0;
39 DateTime? lastClick;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
47
48 final double value;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
48 final double value;
49 final Duration timeout = Duration.zero;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
54
55 final T value;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
70 // A field does not override an inherited setter.
71 int sink = 0;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
77class InferredModel with Diagnosticable {
78 final count = 1;
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
78 final count = 1;
79 final values = <String>[];
The public property isn't described by either `debugFillProperties` or `debugDescribeChildren`.
82class DebugScopeModel with Diagnosticable {
83 final int outsideBody = 1;

Valid

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

class Tile extends StatelessWidget {
  const Tile({
    super.key,
    required this.title,
    required this.count,
    required this.children,
    required this.child,
    this.debugLabel,
  });

  final String title;
  final int count;
  final List<Widget> children;
  final Widget child;
  final String? debugLabel;
  final String _cache = '';

  static const String tag = 'tile';

  bool get enabled => count > 0;

  @override
  Key? get key => super.key;

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties
      ..add(StringProperty('title', title))
      ..add(IntProperty('count', count))
      ..add(StringProperty('label', label))
      ..add(FlagProperty('enabled', value: widget.enabled));
  }

  String get label => debugLabel ?? _cache;

  Tile get widget => this;

  @override
  Widget build(BuildContext context) => child;
}

class Plain {
  Plain(this.value);

  final int value;
}

class InferredModel with Diagnosticable {
  final count = 1;
  final child = const SizedBox();
  final children = <Widget>[const SizedBox()];

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('count', count));
  }
}

Configure diagnostic-describe-all-properties

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "diagnostic-describe-all-properties": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/correctness/diagnostic-describe-all-properties: <reason>
  • discarded-futuresdiscarded_futures

    Don't discard Futures returned by calls in synchronous functions.

  • dispose-fieldsrecommendedflutter

    Requires other owned disposable State fields to be released in dispose().

  • dispose-focus-node-and-timerrecommendedflutter

    Requires owned FocusNode and Timer fields to be released in State.dispose().

  • dispose-provided-instancesrecommendedriverpod

    Flags provider-created instances with a dispose method that lack ref.onDispose cleanup.

  • dispose-provider-resourcesrecommendedriverpod

    Flags provider-created resources without autoDispose or ref.onDispose cleanup.

  • dispose-providersrecommendedprovider

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

  • emit-new-bloc-state-instancesrecommendedbloc

    Flags Bloc and Cubit emissions that reuse their current state instance.

  • exhaustive-casesexhaustive_casesrecommended

    Require switch statements over enum-like classes to cover every constant value.