Skip to content

Commit

Permalink
Update KeepAlive.debugTypicalAncestorWidgetClass (#133498)
Browse files Browse the repository at this point in the history
  • Loading branch information
Piinks authored Sep 13, 2023
1 parent b4953c3 commit 2ea9edc
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 11 deletions.
3 changes: 1 addition & 2 deletions packages/flutter/lib/src/cupertino/dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1577,8 +1577,7 @@ class _ActionButtonParentDataWidget
}

@override
Type get debugTypicalAncestorWidgetClass =>
_CupertinoDialogActionsRenderWidget;
Type get debugTypicalAncestorWidgetClass => _CupertinoDialogActionsRenderWidget;
}

// ParentData applied to individual action buttons that report whether or not
Expand Down
26 changes: 20 additions & 6 deletions packages/flutter/lib/src/widgets/framework.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1592,15 +1592,19 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
return renderObject.parentData is T;
}

/// The [RenderObjectWidget] that is typically used to set up the [ParentData]
/// that [applyParentData] will write to.
/// Describes the [RenderObjectWidget] that is typically used to set up the
/// [ParentData] that [applyParentData] will write to.
///
/// This is only used in error messages to tell users what widget typically
/// wraps this [ParentDataWidget].
/// wraps this [ParentDataWidget] through
/// [debugTypicalAncestorWidgetDescription].
///
/// ## Implementations
///
/// The returned type should be a subclass of `RenderObjectWidget`.
/// The returned Type should describe a subclass of `RenderObjectWidget`. If
/// more than one Type is supported, use
/// [debugTypicalAncestorWidgetDescription], which typically inserts this
/// value but can be overridden to describe more than one Type.
///
/// ```dart
/// @override
Expand All @@ -1612,6 +1616,16 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
/// type is specialized), or specifying the upper bound (e.g. `Foo<Object?>`).
Type get debugTypicalAncestorWidgetClass;

/// Describes the [RenderObjectWidget] that is typically used to set up the
/// [ParentData] that [applyParentData] will write to.
///
/// This is only used in error messages to tell users what widget typically
/// wraps this [ParentDataWidget].
///
/// Returns [debugTypicalAncestorWidgetClass] by default as a String. This can
/// be overridden to describe more than one Type of valid parent.
String get debugTypicalAncestorWidgetDescription => '$debugTypicalAncestorWidgetClass';

Iterable<DiagnosticsNode> _debugDescribeIncorrectParentDataType({
required ParentData? parentData,
RenderObjectWidget? parentDataCreator,
Expand All @@ -1632,7 +1646,7 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget {
),
ErrorHint(
'Usually, this means that the $runtimeType widget has the wrong ancestor RenderObjectWidget. '
'Typically, $runtimeType widgets are placed directly inside $debugTypicalAncestorWidgetClass widgets.',
'Typically, $runtimeType widgets are placed directly inside $debugTypicalAncestorWidgetDescription widgets.',
),
if (parentDataCreator != null)
ErrorHint(
Expand Down Expand Up @@ -6300,7 +6314,7 @@ abstract class RenderObjectElement extends Element {
ErrorSummary('Incorrect use of ParentDataWidget.'),
ErrorDescription('The following ParentDataWidgets are providing parent data to the same RenderObject:'),
for (final ParentDataElement<ParentData> ancestor in badAncestors)
ErrorDescription('- ${ancestor.widget} (typically placed directly inside a ${(ancestor.widget as ParentDataWidget<ParentData>).debugTypicalAncestorWidgetClass} widget)'),
ErrorDescription('- ${ancestor.widget} (typically placed directly inside a ${(ancestor.widget as ParentDataWidget<ParentData>).debugTypicalAncestorWidgetDescription} widget)'),
ErrorDescription('However, a RenderObject can only receive parent data from at most one ParentDataWidget.'),
ErrorHint('Usually, this indicates that at least one of the offending ParentDataWidgets listed above is not placed directly inside a compatible ancestor widget.'),
ErrorDescription('The ownership chain for the RenderObject that received the parent data was:\n ${debugGetCreatorChain(10)}'),
Expand Down
12 changes: 9 additions & 3 deletions packages/flutter/lib/src/widgets/sliver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1311,8 +1311,8 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement {
/// Mark a child as needing to stay alive even when it's in a lazy list that
/// would otherwise remove it.
///
/// This widget is for use in [SliverWithKeepAliveWidget]s, such as
/// [SliverGrid] or [SliverList].
/// This widget is for use in a [RenderAbstractViewport]s, such as
/// [Viewport] or [TwoDimensionalViewport].
///
/// This widget is rarely used directly. The [SliverChildBuilderDelegate] and
/// [SliverChildListDelegate] delegates, used with [SliverList] and
Expand All @@ -1322,6 +1322,9 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement {
/// each child, causing [KeepAlive] widgets to be automatically added and
/// configured in response to [KeepAliveNotification]s.
///
/// The same `addAutomaticKeepAlives` feature is supported by the
/// [TwoDimensionalChildBuilderDelegate] and [TwoDimensionalChildListDelegate].
///
/// Therefore, to keep a widget alive, it is more common to use those
/// notifications than to directly deal with [KeepAlive] widgets.
///
Expand Down Expand Up @@ -1365,7 +1368,10 @@ class KeepAlive extends ParentDataWidget<KeepAliveParentDataMixin> {
bool debugCanApplyOutOfTurn() => keepAlive;

@override
Type get debugTypicalAncestorWidgetClass => SliverWithKeepAliveWidget;
Type get debugTypicalAncestorWidgetClass => throw FlutterError('Multiple Types are supported, use debugTypicalAncestorWidgetDescription.');

@override
String get debugTypicalAncestorWidgetDescription => 'SliverWithKeepAliveWidget or TwoDimensionalViewport';

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
Expand Down
8 changes: 8 additions & 0 deletions packages/flutter/test/widgets/keep_alive_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ List<Widget> generateList(Widget child) {
}

void main() {
test('KeepAlive debugTypicalAncestorWidgetClass', () {
final KeepAlive keepAlive = KeepAlive(keepAlive: false, child: Container());
expect(
keepAlive.debugTypicalAncestorWidgetDescription,
'SliverWithKeepAliveWidget or TwoDimensionalViewport',
);
});

testWidgetsWithLeakTracking('KeepAlive with ListView with itemExtent', (WidgetTester tester) async {
await tester.pumpWidget(
Directionality(
Expand Down

0 comments on commit 2ea9edc

Please sign in to comment.