Commit 156ff2be authored by Ian Hickson's avatar Ian Hickson

Merge pull request #1386 from Hixie/toString

fn3: toString() and toStringDeep() debugging aids
parents 8621892f 4620b632
...@@ -110,6 +110,11 @@ class StockHomeState extends State<StockHome> { ...@@ -110,6 +110,11 @@ class StockHomeState extends State<StockHome> {
icon: 'action/account_balance', icon: 'action/account_balance',
child: new Text('Account Balance') child: new Text('Account Balance')
), ),
new DrawerItem(
icon: 'device/dvr',
onPressed: () { debugDumpApp(); },
child: new Text('Dump App to Console')
),
new DrawerDivider(), new DrawerDivider(),
new DrawerItem( new DrawerItem(
icon: 'action/thumb_up', icon: 'action/thumb_up',
......
...@@ -81,6 +81,12 @@ void runApp(Widget app) { ...@@ -81,6 +81,12 @@ void runApp(Widget app) {
}); });
} }
void debugDumpApp() {
assert(WidgetFlutterBinding.instance != null);
assert(WidgetFlutterBinding.instance.renderViewElement != null);
WidgetFlutterBinding.instance.renderViewElement.toStringDeep().split('\n').forEach(print);
}
/// This class provides a bridge from a RenderObject to an Element tree. The /// This class provides a bridge from a RenderObject to an Element tree. The
/// given container is the RenderObject that the Element tree should be inserted /// given container is the RenderObject that the Element tree should be inserted
/// into. It must be a RenderObject that implements the /// into. It must be a RenderObject that implements the
......
...@@ -177,6 +177,8 @@ abstract class Widget { ...@@ -177,6 +177,8 @@ abstract class Widget {
/// Inflates this configuration to a concrete instance. /// Inflates this configuration to a concrete instance.
Element createElement(); Element createElement();
String toString() => '$runtimeType';
} }
/// RenderObjectWidgets provide the configuration for [RenderObjectElement]s, /// RenderObjectWidgets provide the configuration for [RenderObjectElement]s,
...@@ -346,6 +348,22 @@ abstract class State<T extends StatefulComponent> { ...@@ -346,6 +348,22 @@ abstract class State<T extends StatefulComponent> {
/// the tree at which this component is being built. For example, the context /// the tree at which this component is being built. For example, the context
/// provides the set of inherited widgets for this location in the tree. /// provides the set of inherited widgets for this location in the tree.
Widget build(BuildContext context); Widget build(BuildContext context);
String toString() {
final List<String> data = <String>[];
debugFillDescription(data);
return '$runtimeType(${data.join("; ")})';
}
void debugFillDescription(List<String> description) {
description.add('$hashCode');
if (_debugLifecycleState != _StateLifecycle.ready)
description.add('$_debugLifecycleState');
if (_config == null)
description.add('no config');
if (_element == null)
description.add('not mounted');
}
} }
abstract class ProxyWidget extends StatelessComponent { abstract class ProxyWidget extends StatelessComponent {
...@@ -618,6 +636,35 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -618,6 +636,35 @@ abstract class Element<T extends Widget> implements BuildContext {
void dependenciesChanged() { void dependenciesChanged() {
assert(false); assert(false);
} }
String toString() {
final List<String> data = <String>[];
debugFillDescription(data);
final String name = widget != null ? '$widget' : '[$runtimeType]';
return '$name(${data.join("; ")})';
}
void debugFillDescription(List<String> description) {
if (depth == null)
description.add('no depth');
if (widget == null)
description.add('no widget');
}
String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
String result = '${prefixLineOne}$this\n';
List<Element> children = <Element>[];
visitChildren((Element child) {
children.add(child);
});
if (children.length > 0) {
Element last = children.removeLast();
for (Element child in children)
result += '${child.toStringDeep("$prefixOtherLines \u251C", "$prefixOtherLines \u2502")}';
result += '${last.toStringDeep("$prefixOtherLines \u2514", "$prefixOtherLines ")}';
}
return result;
}
} }
class ErrorWidget extends LeafRenderObjectWidget { class ErrorWidget extends LeafRenderObjectWidget {
...@@ -666,7 +713,7 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -666,7 +713,7 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
/// and by update() when the Widget has changed. /// and by update() when the Widget has changed.
void rebuild() { void rebuild() {
assert(_debugLifecycleState != _ElementLifecycle.initial); assert(_debugLifecycleState != _ElementLifecycle.initial);
if (!_dirty) if (!dirty)
return; return;
assert(_debugLifecycleState == _ElementLifecycle.mounted); assert(_debugLifecycleState == _ElementLifecycle.mounted);
assert(_debugStateLocked); assert(_debugStateLocked);
...@@ -728,8 +775,8 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -728,8 +775,8 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
/// the build itself. /// the build itself.
void markNeedsBuild() { void markNeedsBuild() {
assert(_debugLifecycleState != _ElementLifecycle.defunct); assert(_debugLifecycleState != _ElementLifecycle.defunct);
assert(!_debugStateLocked || (_debugAllowIgnoredCallsToMarkNeedsBuild && _dirty)); assert(!_debugStateLocked || (_debugAllowIgnoredCallsToMarkNeedsBuild && dirty));
if (_dirty) if (dirty)
return; return;
assert(_debugLifecycleState == _ElementLifecycle.mounted); assert(_debugLifecycleState == _ElementLifecycle.mounted);
assert(!_debugStateLocked); assert(!_debugStateLocked);
...@@ -751,6 +798,12 @@ abstract class BuildableElement<T extends Widget> extends Element<T> { ...@@ -751,6 +798,12 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
void dependenciesChanged() { void dependenciesChanged() {
markNeedsBuild(); markNeedsBuild();
} }
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (dirty)
description.add('dirty');
}
} }
/// Instantiation of StatelessComponent widgets. /// Instantiation of StatelessComponent widgets.
...@@ -824,10 +877,16 @@ class StatefulComponentElement extends BuildableElement<StatefulComponent> { ...@@ -824,10 +877,16 @@ class StatefulComponentElement extends BuildableElement<StatefulComponent> {
print('${_state.runtimeType}.dispose failed to call super.dispose'); print('${_state.runtimeType}.dispose failed to call super.dispose');
return false; return false;
}); });
assert(!_dirty); // See BuildableElement.unmount for why this is important. assert(!dirty); // See BuildableElement.unmount for why this is important.
_state._element = null; _state._element = null;
_state = null; _state = null;
} }
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (state != null)
description.add('state: $state');
}
} }
class ParentDataElement extends StatelessComponentElement<ParentDataWidget> { class ParentDataElement extends StatelessComponentElement<ParentDataWidget> {
...@@ -1112,6 +1171,12 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element ...@@ -1112,6 +1171,12 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element
void insertChildRenderObject(RenderObject child, dynamic slot); void insertChildRenderObject(RenderObject child, dynamic slot);
void moveChildRenderObject(RenderObject child, dynamic slot); void moveChildRenderObject(RenderObject child, dynamic slot);
void removeChildRenderObject(RenderObject child); void removeChildRenderObject(RenderObject child);
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (renderObject != null)
description.add('renderObject: $renderObject');
}
} }
/// Instantiation of RenderObjectWidgets that have no children /// Instantiation of RenderObjectWidgets that have no children
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment