debugAssertDoesMeetConstraints method

  1. @override
void debugAssertDoesMeetConstraints()
override

Verify that the object's constraints are being met. Override this function in a subclass to verify that your state matches the constraints object. This function is only called in checked mode and only when needsLayout is false. If the constraints are not met, it should assert or throw an exception.

Implementation

@override
void debugAssertDoesMeetConstraints() {
  assert(() {
    if (!hasSize) {
      final DiagnosticsNode contract;
      if (sizedByParent) {
        contract = ErrorDescription('Because this RenderBox has sizedByParent set to true, it must set its size in performResize().');
      } else {
        contract = ErrorDescription('Because this RenderBox has sizedByParent set to false, it must set its size in performLayout().');
      }
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('RenderBox did not set its size during layout.'),
        contract,
        ErrorDescription('It appears that this did not happen; layout completed, but the size property is still null.'),
        DiagnosticsProperty<RenderBox>('The RenderBox in question is', this, style: DiagnosticsTreeStyle.errorProperty),
      ]);
    }
    // verify that the size is not infinite
    if (!_size!.isFinite) {
      final List<DiagnosticsNode> information = <DiagnosticsNode>[
        ErrorSummary('$runtimeType object was given an infinite size during layout.'),
        ErrorDescription(
          'This probably means that it is a render object that tries to be '
          'as big as possible, but it was put inside another render object '
          'that allows its children to pick their own size.',
        ),
      ];
      if (!constraints.hasBoundedWidth) {
        RenderBox node = this;
        while (!node.constraints.hasBoundedWidth && node.parent is RenderBox) {
          node = node.parent! as RenderBox;
        }

        information.add(node.describeForError('The nearest ancestor providing an unbounded width constraint is'));
      }
      if (!constraints.hasBoundedHeight) {
        RenderBox node = this;
        while (!node.constraints.hasBoundedHeight && node.parent is RenderBox) {
          node = node.parent! as RenderBox;
        }

        information.add(node.describeForError('The nearest ancestor providing an unbounded height constraint is'));
      }
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ...information,
        DiagnosticsProperty<BoxConstraints>('The constraints that applied to the $runtimeType were', constraints, style: DiagnosticsTreeStyle.errorProperty),
        DiagnosticsProperty<Size>('The exact size it was given was', _size, style: DiagnosticsTreeStyle.errorProperty),
        ErrorHint('See https://flutter.cn/docs/development/ui/layout/box-constraints for more information.'),
      ]);
    }
    // verify that the size is within the constraints
    if (!constraints.isSatisfiedBy(_size!)) {
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('$runtimeType does not meet its constraints.'),
        DiagnosticsProperty<BoxConstraints>('Constraints', constraints, style: DiagnosticsTreeStyle.errorProperty),
        DiagnosticsProperty<Size>('Size', _size, style: DiagnosticsTreeStyle.errorProperty),
        ErrorHint(
          'If you are not writing your own RenderBox subclass, then this is not '
          'your fault. Contact support: https://github.com/flutter/flutter/issues/new?template=2_bug.yml',
        ),
      ]);
    }
    if (debugCheckIntrinsicSizes) {
      // verify that the intrinsics are sane
      assert(!RenderObject.debugCheckingIntrinsics);
      RenderObject.debugCheckingIntrinsics = true;
      final List<DiagnosticsNode> failures = <DiagnosticsNode>[];

      double testIntrinsic(double Function(double extent) function, String name, double constraint) {
        final double result = function(constraint);
        if (result < 0) {
          failures.add(ErrorDescription(' * $name($constraint) returned a negative value: $result'));
        }
        if (!result.isFinite) {
          failures.add(ErrorDescription(' * $name($constraint) returned a non-finite value: $result'));
        }
        return result;
      }

      void testIntrinsicsForValues(double Function(double extent) getMin, double Function(double extent) getMax, String name, double constraint) {
        final double min = testIntrinsic(getMin, 'getMinIntrinsic$name', constraint);
        final double max = testIntrinsic(getMax, 'getMaxIntrinsic$name', constraint);
        if (min > max) {
          failures.add(ErrorDescription(' * getMinIntrinsic$name($constraint) returned a larger value ($min) than getMaxIntrinsic$name($constraint) ($max)'));
        }
      }

      testIntrinsicsForValues(getMinIntrinsicWidth, getMaxIntrinsicWidth, 'Width', double.infinity);
      testIntrinsicsForValues(getMinIntrinsicHeight, getMaxIntrinsicHeight, 'Height', double.infinity);
      if (constraints.hasBoundedWidth) {
        testIntrinsicsForValues(getMinIntrinsicWidth, getMaxIntrinsicWidth, 'Width', constraints.maxHeight);
      }
      if (constraints.hasBoundedHeight) {
        testIntrinsicsForValues(getMinIntrinsicHeight, getMaxIntrinsicHeight, 'Height', constraints.maxWidth);
      }

      // TODO(ianh): Test that values are internally consistent in more ways than the above.

      RenderObject.debugCheckingIntrinsics = false;
      if (failures.isNotEmpty) {
        // TODO(jacobr): consider nesting the failures object so it is collapsible.
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('The intrinsic dimension methods of the $runtimeType class returned values that violate the intrinsic protocol contract.'),
          ErrorDescription('The following ${failures.length > 1 ? "failures" : "failure"} was detected:'), // should this be tagged as an error or not?
          ...failures,
          ErrorHint(
            'If you are not writing your own RenderBox subclass, then this is not\n'
            'your fault. Contact support: https://github.com/flutter/flutter/issues/new?template=2_bug.yml',
          ),
        ]);
      }

      // Checking that getDryLayout computes the same size.
      _dryLayoutCalculationValid = true;
      RenderObject.debugCheckingIntrinsics = true;
      final Size dryLayoutSize;
      try {
        dryLayoutSize = getDryLayout(constraints);
      } finally {
        RenderObject.debugCheckingIntrinsics = false;
      }
      if (_dryLayoutCalculationValid && dryLayoutSize != size) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('The size given to the ${objectRuntimeType(this, 'RenderBox')} class differs from the size computed by computeDryLayout.'),
          ErrorDescription(
            'The size computed in ${sizedByParent ? 'performResize' : 'performLayout'} '
            'is $size, which is different from $dryLayoutSize, which was computed by computeDryLayout.',
          ),
          ErrorDescription(
            'The constraints used were $constraints.',
          ),
          ErrorHint(
            'If you are not writing your own RenderBox subclass, then this is not\n'
            'your fault. Contact support: https://github.com/flutter/flutter/issues/new?template=2_bug.yml',
          ),
        ]);
      }
    }
    return true;
  }());
}