Merge pull request #1218 from Hixie/toString
Improve debugging aids for widgets, rendering.
This commit is contained in:
commit
c0d326b17f
@ -588,8 +588,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
String toStringName() {
|
String toString() {
|
||||||
String header = super.toStringName();
|
String header = super.toString();
|
||||||
if (_overflow is double && _overflow > 0.0)
|
if (_overflow is double && _overflow > 0.0)
|
||||||
header += ' OVERFLOWING';
|
header += ' OVERFLOWING';
|
||||||
return header;
|
return header;
|
||||||
|
@ -1041,18 +1041,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
|||||||
// You must not add yourself to /result/ if you return false.
|
// You must not add yourself to /result/ if you return false.
|
||||||
|
|
||||||
|
|
||||||
String toString([String prefix = '']) {
|
|
||||||
RenderObject debugPreviousActiveLayout = _debugActiveLayout;
|
|
||||||
_debugActiveLayout = null;
|
|
||||||
String header = toStringName();
|
|
||||||
prefix += ' ';
|
|
||||||
String result = '${header}\n${debugDescribeSettings(prefix)}${debugDescribeChildren(prefix)}';
|
|
||||||
_debugActiveLayout = debugPreviousActiveLayout;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a human understandable name
|
/// Returns a human understandable name
|
||||||
String toStringName() {
|
String toString() {
|
||||||
String header = '${runtimeType}';
|
String header = '${runtimeType}';
|
||||||
if (_relayoutSubtreeRoot != null && _relayoutSubtreeRoot != this) {
|
if (_relayoutSubtreeRoot != null && _relayoutSubtreeRoot != this) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
@ -1070,7 +1060,25 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
|||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a description of the tree rooted at this node.
|
||||||
|
/// If the prefix argument is provided, then every line in the output
|
||||||
|
/// will be prefixed by that string.
|
||||||
|
String toStringDeep([String prefix = '']) {
|
||||||
|
RenderObject debugPreviousActiveLayout = _debugActiveLayout;
|
||||||
|
_debugActiveLayout = null;
|
||||||
|
prefix += ' ';
|
||||||
|
String result = '$this\n${debugDescribeSettings(prefix)}${debugDescribeChildren(prefix)}';
|
||||||
|
_debugActiveLayout = debugPreviousActiveLayout;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a string describing the current node's fields, one field per line,
|
||||||
|
/// with each line prefixed by the prefix argument. Subclasses should override
|
||||||
|
/// this to have their information included in toStringDeep().
|
||||||
String debugDescribeSettings(String prefix) => '${prefix}parentData: ${parentData}\n${prefix}constraints: ${constraints}\n';
|
String debugDescribeSettings(String prefix) => '${prefix}parentData: ${parentData}\n${prefix}constraints: ${constraints}\n';
|
||||||
|
|
||||||
|
/// Returns a string describing the current node's descendants. Each line of
|
||||||
|
/// the subtree in the output should be indented by the prefix argument.
|
||||||
String debugDescribeChildren(String prefix) => '';
|
String debugDescribeChildren(String prefix) => '';
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1112,7 +1120,7 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem
|
|||||||
}
|
}
|
||||||
String debugDescribeChildren(String prefix) {
|
String debugDescribeChildren(String prefix) {
|
||||||
if (child != null)
|
if (child != null)
|
||||||
return '${prefix}child: ${child.toString(prefix)}';
|
return '${prefix}child: ${child.toStringDeep(prefix)}';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1352,7 +1360,7 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
|
|||||||
int count = 1;
|
int count = 1;
|
||||||
ChildType child = _firstChild;
|
ChildType child = _firstChild;
|
||||||
while (child != null) {
|
while (child != null) {
|
||||||
result += '${prefix}child ${count}: ${child.toString(prefix)}';
|
result += '${prefix}child ${count}: ${child.toStringDeep(prefix)}';
|
||||||
count += 1;
|
count += 1;
|
||||||
child = child.parentData.nextSibling;
|
child = child.parentData.nextSibling;
|
||||||
}
|
}
|
||||||
|
@ -171,12 +171,9 @@ class SkyBinding extends HitTestTarget {
|
|||||||
GestureArena.instance.close(event.pointer);
|
GestureArena.instance.close(event.pointer);
|
||||||
return EventDisposition.processed;
|
return EventDisposition.processed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
String toString() => 'Render Tree:\n${_renderView}';
|
|
||||||
|
|
||||||
/// Prints a textual representation of the entire render tree
|
/// Prints a textual representation of the entire render tree
|
||||||
void debugDumpRenderTree() {
|
void debugDumpRenderTree() {
|
||||||
toString().split('\n').forEach(print);
|
SkyBinding.instance.renderView.toStringDeep().split('\n').forEach(print);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -235,8 +235,10 @@ class Focus extends StatefulComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String toStringName() {
|
void debugAddDetails(List<String> details) {
|
||||||
return '${super.toStringName()}(focusedScope=$_focusedScope; focusedWidget=$_focusedWidget)';
|
super.debugAddDetails(details);
|
||||||
|
details.add('focusedScope=$_focusedScope');
|
||||||
|
details.add('focusedWidget=$_focusedWidget');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,8 @@ abstract class GlobalKey extends Key {
|
|||||||
assert(() {
|
assert(() {
|
||||||
String message = '';
|
String message = '';
|
||||||
for (GlobalKey key in _debugDuplicates.keys) {
|
for (GlobalKey key in _debugDuplicates.keys) {
|
||||||
message += "Duplicate GlobalKey found amongst mounted widgets: $key (${_debugDuplicates[key]} instances)\n";
|
message += 'Duplicate GlobalKey found amongst mounted widgets: $key (${_debugDuplicates[key]} instances)\n';
|
||||||
message += "Most recently registered instance is:\n${_registry[key]}\n";
|
message += 'Most recently registered instance is:\n${_registry[key]}\n';
|
||||||
}
|
}
|
||||||
if (!_debugDuplicates.isEmpty)
|
if (!_debugDuplicates.isEmpty)
|
||||||
throw message;
|
throw message;
|
||||||
@ -288,7 +288,7 @@ abstract class Widget {
|
|||||||
|
|
||||||
static void _notifyMountStatusChanged() {
|
static void _notifyMountStatusChanged() {
|
||||||
try {
|
try {
|
||||||
sky.tracing.begin("Widget._notifyMountStatusChanged");
|
sky.tracing.begin('Widget._notifyMountStatusChanged');
|
||||||
_notifyingMountStatus = true;
|
_notifyingMountStatus = true;
|
||||||
for (Widget node in _mountedChanged) {
|
for (Widget node in _mountedChanged) {
|
||||||
if (node._wasMounted != node._mounted) {
|
if (node._wasMounted != node._mounted) {
|
||||||
@ -302,7 +302,7 @@ abstract class Widget {
|
|||||||
_mountedChanged.clear();
|
_mountedChanged.clear();
|
||||||
} finally {
|
} finally {
|
||||||
_notifyingMountStatus = false;
|
_notifyingMountStatus = false;
|
||||||
sky.tracing.end("Widget._notifyMountStatusChanged");
|
sky.tracing.end('Widget._notifyMountStatusChanged');
|
||||||
}
|
}
|
||||||
GlobalKey._notifyListeners();
|
GlobalKey._notifyListeners();
|
||||||
}
|
}
|
||||||
@ -404,7 +404,7 @@ abstract class Widget {
|
|||||||
String debugDetails;
|
String debugDetails;
|
||||||
assert(() {
|
assert(() {
|
||||||
// we save this information early because by the time the exception fires we might have changed everything around
|
// we save this information early because by the time the exception fires we might have changed everything around
|
||||||
debugDetails = " old child: ${oldNode?.toStringName()}\n new child: ${newNode?.toStringName()}";
|
debugDetails = ' old child: $oldNode\n new child: $newNode';
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@ -508,36 +508,28 @@ abstract class Widget {
|
|||||||
return newNode;
|
return newNode;
|
||||||
|
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
_debugReportException('syncing children of ${this.toStringName()}\n$debugDetails', e, stack);
|
_debugReportException('syncing children of $this\n$debugDetails', e, stack);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _adjustPrefixWithParentCheck(Widget child, String prefix) {
|
// This function can be safely called when the layout is valid.
|
||||||
if (child.parent == this)
|
// For example Listener or SizeObserver callbacks can safely call
|
||||||
return prefix;
|
// globalToLocal().
|
||||||
if (child.parent == null)
|
Point globalToLocal(Point point) {
|
||||||
return '$prefix [[DISCONNECTED]] ';
|
assert(mounted);
|
||||||
return '$prefix [[PARENT IS ${child.parent.toStringName()}]] ';
|
assert(renderObject is RenderBox);
|
||||||
|
return (renderObject as RenderBox).globalToLocal(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString([String prefix = '', String startPrefix = '']) {
|
// See globalToLocal().
|
||||||
String childrenString = '';
|
Point localToGlobal(Point point) {
|
||||||
List<Widget> children = new List<Widget>();
|
assert(mounted);
|
||||||
walkChildren(children.add);
|
assert(renderObject is RenderBox);
|
||||||
if (children.length > 0) {
|
return (renderObject as RenderBox).localToGlobal(point);
|
||||||
Widget lastChild = children.removeLast();
|
|
||||||
String nextStartPrefix = prefix + ' +-';
|
|
||||||
String nextPrefix = prefix + ' | ';
|
|
||||||
for (Widget child in children)
|
|
||||||
childrenString += child.toString(nextPrefix, _adjustPrefixWithParentCheck(child, nextStartPrefix));
|
|
||||||
nextStartPrefix = prefix + ' \'-';
|
|
||||||
nextPrefix = prefix + ' ';
|
|
||||||
childrenString += lastChild.toString(nextPrefix, _adjustPrefixWithParentCheck(lastChild, nextStartPrefix));
|
|
||||||
}
|
}
|
||||||
return '$startPrefix${toStringName()}\n$childrenString';
|
|
||||||
}
|
String toString() {
|
||||||
String toStringName() {
|
|
||||||
List<String> details = <String>[];
|
List<String> details = <String>[];
|
||||||
debugAddDetails(details);
|
debugAddDetails(details);
|
||||||
String detailString = details.join('; ');
|
String detailString = details.join('; ');
|
||||||
@ -558,21 +550,28 @@ abstract class Widget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String toStringDeep([String prefix = '', String startPrefix = '']) {
|
||||||
// This function can be safely called when the layout is valid.
|
String childrenString = '';
|
||||||
// For example Listener or SizeObserver callbacks can safely call
|
List<Widget> children = new List<Widget>();
|
||||||
// globalToLocal().
|
walkChildren(children.add);
|
||||||
Point globalToLocal(Point point) {
|
if (children.length > 0) {
|
||||||
assert(mounted);
|
Widget lastChild = children.removeLast();
|
||||||
assert(renderObject is RenderBox);
|
String nextStartPrefix = prefix + ' +-';
|
||||||
return (renderObject as RenderBox).globalToLocal(point);
|
String nextPrefix = prefix + ' | ';
|
||||||
|
for (Widget child in children)
|
||||||
|
childrenString += child.toStringDeep(nextPrefix, _adjustPrefixWithParentCheck(child, nextStartPrefix));
|
||||||
|
nextStartPrefix = prefix + ' \'-';
|
||||||
|
nextPrefix = prefix + ' ';
|
||||||
|
childrenString += lastChild.toStringDeep(nextPrefix, _adjustPrefixWithParentCheck(lastChild, nextStartPrefix));
|
||||||
}
|
}
|
||||||
|
return '$startPrefix$this\n$childrenString';
|
||||||
// See globalToLocal().
|
}
|
||||||
Point localToGlobal(Point point) {
|
String _adjustPrefixWithParentCheck(Widget child, String prefix) {
|
||||||
assert(mounted);
|
if (child.parent == this)
|
||||||
assert(renderObject is RenderBox);
|
return prefix;
|
||||||
return (renderObject as RenderBox).localToGlobal(point);
|
if (child.parent == null)
|
||||||
|
return '$prefix [[DISCONNECTED]] ';
|
||||||
|
return '$prefix [[PARENT IS ${child.parent}]] ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,7 +806,7 @@ abstract class Component extends Widget {
|
|||||||
_child = build();
|
_child = build();
|
||||||
assert(_child != null);
|
assert(_child != null);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
_debugReportException("building ${this.toStringName()}", e, stack);
|
_debugReportException('building $this', e, stack);
|
||||||
}
|
}
|
||||||
_currentOrder = lastOrder;
|
_currentOrder = lastOrder;
|
||||||
assert(() { _debugChildTaken = false; return true; });
|
assert(() { _debugChildTaken = false; return true; });
|
||||||
@ -817,7 +816,7 @@ abstract class Component extends Widget {
|
|||||||
assert(!_debugChildTaken); // we shouldn't be able to lose our child when we're syncing it!
|
assert(!_debugChildTaken); // we shouldn't be able to lose our child when we're syncing it!
|
||||||
assert(_child == null || _child.parent == this);
|
assert(_child == null || _child.parent == this);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
_debugReportException('syncing build output of ${this.toStringName()}\n old child: ${oldChild?.toStringName()}\n new child: ${_child?.toStringName()}', e, stack);
|
_debugReportException('syncing build output of $this\n old child: $oldChild\n new child: $_child', e, stack);
|
||||||
_child = null;
|
_child = null;
|
||||||
}
|
}
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -1100,7 +1099,7 @@ abstract class RenderObjectWrapper extends Widget {
|
|||||||
assert(_renderObject != null);
|
assert(_renderObject != null);
|
||||||
}
|
}
|
||||||
assert(() {
|
assert(() {
|
||||||
_renderObject.debugExceptionContext = Component._debugComponentBuildTree.fold(' Widget build stack:', (String s, Component c) => s + '\n ${c.toStringName()}');
|
_renderObject.debugExceptionContext = Component._debugComponentBuildTree.fold(' Widget build stack:', (String result, Component component) => result + '\n $component');
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
assert(_renderObject == renderObject); // in case a subclass reintroduces it
|
assert(_renderObject == renderObject); // in case a subclass reintroduces it
|
||||||
@ -1443,7 +1442,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
|
|||||||
continue; // when these nodes are reordered, we just reassign the data
|
continue; // when these nodes are reordered, we just reassign the data
|
||||||
|
|
||||||
if (!idSet.add(child.key)) {
|
if (!idSet.add(child.key)) {
|
||||||
throw '''If multiple keyed nodes exist as children of another node, they must have unique keys. ${toStringName()} has multiple children with key "${child.key}".''';
|
throw 'If multiple keyed nodes exist as children of another node, they must have unique keys. $this has multiple children with key "${child.key}".';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1579,11 +1578,13 @@ void runApp(App app, { RenderView renderViewOverride, bool enableProfilingLoop:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints a textual representation of the entire widget tree
|
||||||
void debugDumpApp() {
|
void debugDumpApp() {
|
||||||
if (_container != null)
|
if (_container != null)
|
||||||
_container.toString().split('\n').forEach(print);
|
_container.toStringDeep().split('\n').forEach(print);
|
||||||
else
|
else
|
||||||
print("runApp() not yet called");
|
print('runApp() not yet called');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1639,7 +1640,7 @@ void _debugReportException(String context, dynamic exception, StackTrace stack)
|
|||||||
print('Stack trace:');
|
print('Stack trace:');
|
||||||
'$stack'.split('\n').forEach(print);
|
'$stack'.split('\n').forEach(print);
|
||||||
print('Build stack:');
|
print('Build stack:');
|
||||||
Component._debugComponentBuildTree.forEach((Component c) { print(' ${c.toStringName()}'); });
|
Component._debugComponentBuildTree.forEach((Component component) { print(' $component'); });
|
||||||
print('Current application widget tree:');
|
print('Current application widget tree:');
|
||||||
debugDumpApp();
|
debugDumpApp();
|
||||||
print('------------------------------------------------------------------------');
|
print('------------------------------------------------------------------------');
|
||||||
|
@ -171,7 +171,7 @@ class RenderScaffold extends RenderBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String debugDescribeChildren(String prefix) {
|
String debugDescribeChildren(String prefix) {
|
||||||
return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toString(prefix)}').join();
|
return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toStringDeep(prefix)}').join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user