Repository: flutter
Issue: Add lints to catch common DiagnosticsProperty related bugs
Labels: team,framework,dependency: dart,P2,team-framework,triaged-framework

The goal of these lints is to catch cases where a developer added properties to a class implementing Diagnosticable class but forgot to update the debugFillProperties method to include the properties.

Additionally we can add lints for trivial to spot cases where the right DiagnosticsProperty subclass wasn't used for a particular value type.

## Candidate lints to add:
* Lint that warns about properties that exist in a class but are not referenced by debugFillProperties. Key for this lint being useful is to keep false positives to a minimum by counting any reference to a property in the debugFillProperties or describeChildren calls and providing an escape hatch.
* Lint that warns when a DiagnosticsProperty is used instead of EnumProperty for values of type enum.
* Lint that warns when DiagnosticsProperty is used instead of StringProperty, IntProperty, or DoubleProperty for a value of type String, int, or Double.
* Lint that returns an error if EnumProperty is used with a type that isn't an enum (if Dart's type system had an enum base class we wouldn't have to do it).
* Lint that warns when DiagnosticsProperty is used instead of TransformProperty for Matrix objects.

Example bug that would have been caught earlier if we had a lint for EnumProperty: https://github.com/flutter/flutter/pull/27224/files

There are cases where a class has properties that are never mentioned anywhere inside the contents of debugFillProperties and that is a good thing as the property value is not useful to show for debugging. Much of the value of debugFillProperties vs simply showing all properties is the curation of what properties are relevant to show.
Provide an escape hatch annotation in `package:meta` perhaps called  `@debuggerHidden` that when applied to a properties or fields indicates that it is intentional that they are excluded from debugFillProperties. The lint warning for missing properties will specify exactly the change you need to make to add the annotation to properly mark the properties as intentionally omitted.
The annotation is a generally useful feature for debuggers with prior art of similar work in many platforms. For example [.net ](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.debuggerhiddenattribute?view=netframework-4.7.2)provides a debuggerHiddenAttribute annotation indicating fields to hide by default in debuggers.
With this annotations Dart debugging tools such as VSCode can do a better job of displaying objects as they know which properties are useful to users and which should be hidden by default.

Example of how this would apply to the Element class:
```dart
class Element { 
  bool _dirty = true;

  // Whether this is in owner._dirtyElements. This is used to know whether we
  // should be adding the element back into the list when it's reactivated.
 @hideForDebugging bool _inDirtyList = false;

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle= DiagnosticsTreeStyle.dense;
    properties.add(ObjectFlagProperty<int>('depth', depth, ifNull: 'no depth'));
    properties.add(ObjectFlagProperty<Widget>('widget', widget, ifNull: 'no widget'));
    if (widget != null) {
      properties.add(DiagnosticsProperty<Key>('key', widget?.key, showName: false, defaultValue: null, level: DiagnosticLevel.hidden));
      widget.debugFillProperties(properties);
    }
    properties.add(FlagProperty('dirty', value: dirty, ifTrue: 'dirty'));
  }
}
````
Additional example: 
There was a bug in the debugFillProperty method for UnconstrainedBox where the value of 'constrainedAxis' was always set to null and a property that was an EnumProperty was not listed as an EnumProperty which misses the nice EnumProperty syntax. 
```dart
class UnconstrainedBox extends SingleChildRenderObjectWidget {
  /// Creates a widget that imposes no constraints on its child, allowing it to
  /// render at its "natural" size. If the child overflows the parents
  /// constraints, a warning will be given in debug mode.
  const UnconstrainedBox({
    Key key,
    Widget child,
    this.textDirection,
    this.alignment = Alignment.center,
    this.constrainedAxis,
  }) : assert(alignment != null),
       super(key: key, child: child);

  /// The text direction to use when interpreting the [alignment] if it is an
  /// [AlignmentDirectional].
  final TextDirection textDirection;

  /// The alignment to use when laying out the child.
  ///
  /// If this is an [AlignmentDirectional], then [textDirection] must not be
  /// null.
  ///
  /// See also:
  ///
  ///  * [Alignment] for non-[Directionality]-aware alignments.
  ///  * [AlignmentDirectional] for [Directionality]-aware alignments.
  final AlignmentGeometry alignment;

  /// The axis to retain constraints on, if any.
  ///
  /// If not set, or set to null (the default), neither axis will retain its
  /// constraints. If set to [Axis.vertical], then vertical constraints will
  /// be retained, and if set to [Axis.horizontal], then horizontal constraints
  /// will be retained.
  final Axis constrainedAxis; //  <-- This is an enum type.

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
    properties.add(DiagnosticsProperty<Axis>('constrainedAxis', null));
    properties.add(DiagnosticsProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
  }
}
```