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 header = super.toStringName();
|
||||
String toString() {
|
||||
String header = super.toString();
|
||||
if (_overflow is double && _overflow > 0.0)
|
||||
header += ' OVERFLOWING';
|
||||
return header;
|
||||
|
@ -1041,18 +1041,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
// 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
|
||||
String toStringName() {
|
||||
String toString() {
|
||||
String header = '${runtimeType}';
|
||||
if (_relayoutSubtreeRoot != null && _relayoutSubtreeRoot != this) {
|
||||
int count = 1;
|
||||
@ -1070,7 +1060,25 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
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';
|
||||
|
||||
/// 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) => '';
|
||||
|
||||
}
|
||||
@ -1112,7 +1120,7 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem
|
||||
}
|
||||
String debugDescribeChildren(String prefix) {
|
||||
if (child != null)
|
||||
return '${prefix}child: ${child.toString(prefix)}';
|
||||
return '${prefix}child: ${child.toStringDeep(prefix)}';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@ -1352,7 +1360,7 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
|
||||
int count = 1;
|
||||
ChildType child = _firstChild;
|
||||
while (child != null) {
|
||||
result += '${prefix}child ${count}: ${child.toString(prefix)}';
|
||||
result += '${prefix}child ${count}: ${child.toStringDeep(prefix)}';
|
||||
count += 1;
|
||||
child = child.parentData.nextSibling;
|
||||
}
|
||||
|
@ -171,12 +171,9 @@ class SkyBinding extends HitTestTarget {
|
||||
GestureArena.instance.close(event.pointer);
|
||||
return EventDisposition.processed;
|
||||
}
|
||||
|
||||
String toString() => 'Render Tree:\n${_renderView}';
|
||||
|
||||
/// Prints a textual representation of the entire render tree
|
||||
void debugDumpRenderTree() {
|
||||
toString().split('\n').forEach(print);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Prints a textual representation of the entire render tree
|
||||
void debugDumpRenderTree() {
|
||||
SkyBinding.instance.renderView.toStringDeep().split('\n').forEach(print);
|
||||
}
|
||||
|
@ -235,8 +235,10 @@ class Focus extends StatefulComponent {
|
||||
}
|
||||
}
|
||||
|
||||
String toStringName() {
|
||||
return '${super.toStringName()}(focusedScope=$_focusedScope; focusedWidget=$_focusedWidget)';
|
||||
void debugAddDetails(List<String> details) {
|
||||
super.debugAddDetails(details);
|
||||
details.add('focusedScope=$_focusedScope');
|
||||
details.add('focusedWidget=$_focusedWidget');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -139,8 +139,8 @@ abstract class GlobalKey extends Key {
|
||||
assert(() {
|
||||
String message = '';
|
||||
for (GlobalKey key in _debugDuplicates.keys) {
|
||||
message += "Duplicate GlobalKey found amongst mounted widgets: $key (${_debugDuplicates[key]} instances)\n";
|
||||
message += "Most recently registered instance is:\n${_registry[key]}\n";
|
||||
message += 'Duplicate GlobalKey found amongst mounted widgets: $key (${_debugDuplicates[key]} instances)\n';
|
||||
message += 'Most recently registered instance is:\n${_registry[key]}\n';
|
||||
}
|
||||
if (!_debugDuplicates.isEmpty)
|
||||
throw message;
|
||||
@ -288,7 +288,7 @@ abstract class Widget {
|
||||
|
||||
static void _notifyMountStatusChanged() {
|
||||
try {
|
||||
sky.tracing.begin("Widget._notifyMountStatusChanged");
|
||||
sky.tracing.begin('Widget._notifyMountStatusChanged');
|
||||
_notifyingMountStatus = true;
|
||||
for (Widget node in _mountedChanged) {
|
||||
if (node._wasMounted != node._mounted) {
|
||||
@ -302,7 +302,7 @@ abstract class Widget {
|
||||
_mountedChanged.clear();
|
||||
} finally {
|
||||
_notifyingMountStatus = false;
|
||||
sky.tracing.end("Widget._notifyMountStatusChanged");
|
||||
sky.tracing.end('Widget._notifyMountStatusChanged');
|
||||
}
|
||||
GlobalKey._notifyListeners();
|
||||
}
|
||||
@ -404,7 +404,7 @@ abstract class Widget {
|
||||
String debugDetails;
|
||||
assert(() {
|
||||
// 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;
|
||||
});
|
||||
try {
|
||||
@ -508,36 +508,28 @@ abstract class Widget {
|
||||
return newNode;
|
||||
|
||||
} catch (e, stack) {
|
||||
_debugReportException('syncing children of ${this.toStringName()}\n$debugDetails', e, stack);
|
||||
_debugReportException('syncing children of $this\n$debugDetails', e, stack);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String _adjustPrefixWithParentCheck(Widget child, String prefix) {
|
||||
if (child.parent == this)
|
||||
return prefix;
|
||||
if (child.parent == null)
|
||||
return '$prefix [[DISCONNECTED]] ';
|
||||
return '$prefix [[PARENT IS ${child.parent.toStringName()}]] ';
|
||||
// This function can be safely called when the layout is valid.
|
||||
// For example Listener or SizeObserver callbacks can safely call
|
||||
// globalToLocal().
|
||||
Point globalToLocal(Point point) {
|
||||
assert(mounted);
|
||||
assert(renderObject is RenderBox);
|
||||
return (renderObject as RenderBox).globalToLocal(point);
|
||||
}
|
||||
|
||||
String toString([String prefix = '', String startPrefix = '']) {
|
||||
String childrenString = '';
|
||||
List<Widget> children = new List<Widget>();
|
||||
walkChildren(children.add);
|
||||
if (children.length > 0) {
|
||||
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';
|
||||
// See globalToLocal().
|
||||
Point localToGlobal(Point point) {
|
||||
assert(mounted);
|
||||
assert(renderObject is RenderBox);
|
||||
return (renderObject as RenderBox).localToGlobal(point);
|
||||
}
|
||||
String toStringName() {
|
||||
|
||||
String toString() {
|
||||
List<String> details = <String>[];
|
||||
debugAddDetails(details);
|
||||
String detailString = details.join('; ');
|
||||
@ -558,21 +550,28 @@ abstract class Widget {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function can be safely called when the layout is valid.
|
||||
// For example Listener or SizeObserver callbacks can safely call
|
||||
// globalToLocal().
|
||||
Point globalToLocal(Point point) {
|
||||
assert(mounted);
|
||||
assert(renderObject is RenderBox);
|
||||
return (renderObject as RenderBox).globalToLocal(point);
|
||||
String toStringDeep([String prefix = '', String startPrefix = '']) {
|
||||
String childrenString = '';
|
||||
List<Widget> children = new List<Widget>();
|
||||
walkChildren(children.add);
|
||||
if (children.length > 0) {
|
||||
Widget lastChild = children.removeLast();
|
||||
String nextStartPrefix = prefix + ' +-';
|
||||
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) {
|
||||
assert(mounted);
|
||||
assert(renderObject is RenderBox);
|
||||
return (renderObject as RenderBox).localToGlobal(point);
|
||||
String _adjustPrefixWithParentCheck(Widget child, String prefix) {
|
||||
if (child.parent == this)
|
||||
return prefix;
|
||||
if (child.parent == null)
|
||||
return '$prefix [[DISCONNECTED]] ';
|
||||
return '$prefix [[PARENT IS ${child.parent}]] ';
|
||||
}
|
||||
}
|
||||
|
||||
@ -807,7 +806,7 @@ abstract class Component extends Widget {
|
||||
_child = build();
|
||||
assert(_child != null);
|
||||
} catch (e, stack) {
|
||||
_debugReportException("building ${this.toStringName()}", e, stack);
|
||||
_debugReportException('building $this', e, stack);
|
||||
}
|
||||
_currentOrder = lastOrder;
|
||||
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(_child == null || _child.parent == this);
|
||||
} 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;
|
||||
}
|
||||
assert(() {
|
||||
@ -1100,7 +1099,7 @@ abstract class RenderObjectWrapper extends Widget {
|
||||
assert(_renderObject != null);
|
||||
}
|
||||
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;
|
||||
});
|
||||
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
|
||||
|
||||
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;
|
||||
@ -1579,11 +1578,13 @@ void runApp(App app, { RenderView renderViewOverride, bool enableProfilingLoop:
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints a textual representation of the entire widget tree
|
||||
void debugDumpApp() {
|
||||
if (_container != null)
|
||||
_container.toString().split('\n').forEach(print);
|
||||
_container.toStringDeep().split('\n').forEach(print);
|
||||
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:');
|
||||
'$stack'.split('\n').forEach(print);
|
||||
print('Build stack:');
|
||||
Component._debugComponentBuildTree.forEach((Component c) { print(' ${c.toStringName()}'); });
|
||||
Component._debugComponentBuildTree.forEach((Component component) { print(' $component'); });
|
||||
print('Current application widget tree:');
|
||||
debugDumpApp();
|
||||
print('------------------------------------------------------------------------');
|
||||
|
@ -171,7 +171,7 @@ class RenderScaffold extends RenderBox {
|
||||
}
|
||||
|
||||
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