Fix for endless recursion for getLayoutExplorerNode on a Tooltip (#131486)
 Fixes https://github.com/flutter/devtools/issues/5946 While preparing DevTools for the Multi View changes, I noticed that inspecting a Tooltip causes an stack overflow. This PR addresses that issue by fixing the scope of the subtreeDepth variable and adding some other idiomatic fixes
This commit is contained in:
parent
dc4ab0f5df
commit
f80ff55a76
@ -2109,24 +2109,35 @@ mixin WidgetInspectorService {
|
|||||||
summaryTree: true,
|
summaryTree: true,
|
||||||
subtreeDepth: subtreeDepth,
|
subtreeDepth: subtreeDepth,
|
||||||
service: this,
|
service: this,
|
||||||
addAdditionalPropertiesCallback: (DiagnosticsNode node, InspectorSerializationDelegate delegate) {
|
addAdditionalPropertiesCallback:
|
||||||
|
(DiagnosticsNode node, InspectorSerializationDelegate delegate) {
|
||||||
final Object? value = node.value;
|
final Object? value = node.value;
|
||||||
final RenderObject? renderObject = value is Element ? value.renderObject : null;
|
final RenderObject? renderObject =
|
||||||
|
value is Element ? value.renderObject : null;
|
||||||
if (renderObject == null) {
|
if (renderObject == null) {
|
||||||
return const <String, Object>{};
|
return const <String, Object>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
final DiagnosticsSerializationDelegate renderObjectSerializationDelegate = delegate.copyWith(
|
final DiagnosticsSerializationDelegate
|
||||||
|
renderObjectSerializationDelegate = delegate.copyWith(
|
||||||
subtreeDepth: 0,
|
subtreeDepth: 0,
|
||||||
includeProperties: true,
|
includeProperties: true,
|
||||||
expandPropertyValues: false,
|
expandPropertyValues: false,
|
||||||
);
|
);
|
||||||
final Map<String, Object> additionalJson = <String, Object>{
|
final Map<String, Object> additionalJson = <String, Object>{
|
||||||
'renderObject': renderObject.toDiagnosticsNode().toJsonMap(renderObjectSerializationDelegate),
|
// Only include renderObject properties separately if this value is not already the renderObject.
|
||||||
|
// Only include if we are expanding property values to mitigate the risk of infinite loops if
|
||||||
|
// RenderObjects have properties that are Element objects.
|
||||||
|
if (value is! RenderObject && delegate.expandPropertyValues)
|
||||||
|
'renderObject': renderObject
|
||||||
|
.toDiagnosticsNode()
|
||||||
|
.toJsonMap(renderObjectSerializationDelegate),
|
||||||
};
|
};
|
||||||
|
|
||||||
final RenderObject? renderParent = renderObject.parent;
|
final RenderObject? renderParent = renderObject.parent;
|
||||||
if (renderParent is RenderObject && subtreeDepth > 0) {
|
if (renderParent != null &&
|
||||||
|
delegate.subtreeDepth > 0 &&
|
||||||
|
delegate.expandPropertyValues) {
|
||||||
final Object? parentCreator = renderParent.debugCreator;
|
final Object? parentCreator = renderParent.debugCreator;
|
||||||
if (parentCreator is DebugCreator) {
|
if (parentCreator is DebugCreator) {
|
||||||
additionalJson['parentRenderElement'] =
|
additionalJson['parentRenderElement'] =
|
||||||
@ -2147,7 +2158,7 @@ mixin WidgetInspectorService {
|
|||||||
if (!renderObject.debugNeedsLayout) {
|
if (!renderObject.debugNeedsLayout) {
|
||||||
// ignore: invalid_use_of_protected_member
|
// ignore: invalid_use_of_protected_member
|
||||||
final Constraints constraints = renderObject.constraints;
|
final Constraints constraints = renderObject.constraints;
|
||||||
final Map<String, Object>constraintsProperty = <String, Object>{
|
final Map<String, Object> constraintsProperty = <String, Object>{
|
||||||
'type': constraints.runtimeType.toString(),
|
'type': constraints.runtimeType.toString(),
|
||||||
'description': constraints.toString(),
|
'description': constraints.toString(),
|
||||||
};
|
};
|
||||||
|
@ -4771,6 +4771,53 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
|
|||||||
}
|
}
|
||||||
expect(error, isNull);
|
expect(error, isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'ext.flutter.inspector.getLayoutExplorerNode, on a ToolTip, does not throw StackOverflowError',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/devtools/issues/5946
|
||||||
|
const Widget widget = MaterialApp(
|
||||||
|
home: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Center(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Flexible(
|
||||||
|
child: ColoredBox(
|
||||||
|
color: Colors.green,
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'a',
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: null,
|
||||||
|
child: Text('a'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpWidget(widget);
|
||||||
|
|
||||||
|
final Element elevatedButton =
|
||||||
|
tester.element(find.byType(ElevatedButton).first);
|
||||||
|
service.setSelection(elevatedButton, group);
|
||||||
|
|
||||||
|
final String id = service.toId(elevatedButton, group)!;
|
||||||
|
|
||||||
|
Object? error;
|
||||||
|
try {
|
||||||
|
await service.testExtension(
|
||||||
|
WidgetInspectorServiceExtensions.getLayoutExplorerNode.name,
|
||||||
|
<String, String>{'id': id, 'groupName': group, 'subtreeDepth': '1'},
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
expect(error, isNull);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ext.flutter.inspector.structuredErrors', () async {
|
test('ext.flutter.inspector.structuredErrors', () async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user