Commit 01778c48 authored by Hixie's avatar Hixie

Provide hooks for when exceptions are thrown.

This might be helpful for #1219.

Also, remove inDebugMode since it's redundant with just using asserts,
which compile entirely out in release mode.
parent 4467a268
...@@ -444,28 +444,36 @@ abstract class RenderBox extends RenderObject { ...@@ -444,28 +444,36 @@ abstract class RenderBox extends RenderObject {
/// of those functins, call [markNeedsLayout] instead to schedule a layout of /// of those functins, call [markNeedsLayout] instead to schedule a layout of
/// the box. /// the box.
Size get size { Size get size {
if (_size is _DebugSize) { assert(() {
final _DebugSize _size = this._size; // TODO(ianh): Remove this once the analyzer is cleverer if (_size is _DebugSize) {
assert(_size._owner == this); final _DebugSize _size = this._size; // TODO(ianh): Remove this once the analyzer is cleverer
if (RenderObject.debugActiveLayout != null) { assert(_size._owner == this);
// we are always allowed to access our own size (for print debugging and asserts if nothing else) if (RenderObject.debugActiveLayout != null) {
// other than us, the only object that's allowed to read our size is our parent, if they're said they will // we are always allowed to access our own size (for print debugging and asserts if nothing else)
// if you hit this assert trying to access a child's size, pass parentUsesSize: true in layout() // other than us, the only object that's allowed to read our size is our parent, if they're said they will
assert(debugDoingThisResize || debugDoingThisLayout || // if you hit this assert trying to access a child's size, pass parentUsesSize: true in layout()
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent)); assert(debugDoingThisResize || debugDoingThisLayout ||
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent));
}
assert(_size == this._size); // TODO(ianh): Remove this once the analyzer is cleverer
} }
assert(_size == this._size); // TODO(ianh): Remove this once the analyzer is cleverer return true;
} });
return _size; return _size;
} }
void set size(Size value) { void set size(Size value) {
assert((sizedByParent && debugDoingThisResize) || assert((sizedByParent && debugDoingThisResize) ||
(!sizedByParent && debugDoingThisLayout)); (!sizedByParent && debugDoingThisLayout));
if (value is _DebugSize) { assert(() {
assert(value._canBeUsedByParent); if (value is _DebugSize)
assert(value._owner.parent == this); return value._canBeUsedByParent && value._owner.parent == this;
} return true;
_size = inDebugBuild ? new _DebugSize(value, this, debugCanParentUseSize) : value; });
_size = value;
assert(() {
_size = new _DebugSize(_size, this, debugCanParentUseSize);
return true;
});
assert(debugDoesMeetConstraints()); assert(debugDoesMeetConstraints());
} }
......
...@@ -4,19 +4,6 @@ ...@@ -4,19 +4,6 @@
import 'dart:sky' as sky; import 'dart:sky' as sky;
/// Indicates whether we're running with asserts enabled.
final bool inDebugBuild = _initInDebugBuild();
bool _initInDebugBuild() {
bool _inDebug = false;
bool setAssert() {
_inDebug = true;
return true;
}
assert(setAssert());
return _inDebug;
}
/// Causes each RenderBox to paint a box around its bounds. /// Causes each RenderBox to paint a box around its bounds.
bool debugPaintSizeEnabled = false; bool debugPaintSizeEnabled = false;
...@@ -43,6 +30,3 @@ bool debugPaintBoundsEnabled = false; ...@@ -43,6 +30,3 @@ bool debugPaintBoundsEnabled = false;
/// The color to use when painting RenderError boxes in checked mode. /// The color to use when painting RenderError boxes in checked mode.
sky.Color debugErrorBoxColor = const sky.Color(0xFFFF0000); sky.Color debugErrorBoxColor = const sky.Color(0xFFFF0000);
/// How many lines of debugging output to include when an exception is reported.
int debugRenderObjectDumpMaxLength = 10;
...@@ -368,6 +368,17 @@ typedef void RenderObjectVisitor(RenderObject child); ...@@ -368,6 +368,17 @@ typedef void RenderObjectVisitor(RenderObject child);
typedef void LayoutCallback(Constraints constraints); typedef void LayoutCallback(Constraints constraints);
typedef double ExtentCallback(Constraints constraints); typedef double ExtentCallback(Constraints constraints);
typedef void RenderingExceptionHandler(RenderObject source, String method, dynamic exception, StackTrace stack);
/// This callback is invoked whenever an exception is caught by the rendering
/// system. The 'source' argument is the [RenderObject] object that caught the
/// exception. The 'method' argument is the method in which the exception
/// occurred; it will be one of 'performResize', 'performLayout, or 'paint'. The
/// 'exception' argument contains the object that was thrown, and the 'stack'
/// argument contains the stack trace. The callback is invoked after the
/// information is printed to the console, and could be used to print additional
/// information, such as from [debugDumpRenderTree()].
RenderingExceptionHandler debugRenderingExceptionHandler;
/// An object in the render tree /// An object in the render tree
/// ///
/// Render objects have a reference to their parent but do not commit to a model /// Render objects have a reference to their parent but do not commit to a model
...@@ -445,10 +456,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -445,10 +456,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
print('$exception'); print('$exception');
print('Stack trace:'); print('Stack trace:');
print('$stack'); print('$stack');
'The following RenderObject was being processed when the exception was fired (limited to $debugRenderObjectDumpMaxLength lines):\n${this}' print('The following RenderObject was being processed when the exception was fired:\n${this}');
.split('\n').take(debugRenderObjectDumpMaxLength+1).forEach(print);
if (debugExceptionContext != '') if (debugExceptionContext != '')
'The RenderObject had the following exception context:\n${debugExceptionContext}'.split('\n').forEach(print); 'That RenderObject had the following exception context:\n${debugExceptionContext}'.split('\n').forEach(print);
if (debugRenderingExceptionHandler != null)
debugRenderingExceptionHandler(this, method, exception, stack);
} }
static bool _debugDoingLayout = false; static bool _debugDoingLayout = false;
......
...@@ -1655,6 +1655,16 @@ class ErrorWidget extends LeafRenderObjectWrapper { ...@@ -1655,6 +1655,16 @@ class ErrorWidget extends LeafRenderObjectWrapper {
RenderBox createNode() => new RenderErrorBox(); RenderBox createNode() => new RenderErrorBox();
} }
typedef void WidgetsExceptionHandler(String context, dynamic exception, StackTrace stack);
/// This callback is invoked whenever an exception is caught by the widget
/// system. The 'context' argument is a description of what was happening when
/// the exception occurred, and may include additional details such as
/// descriptions of the objects involved. The 'exception' argument contains the
/// object that was thrown, and the 'stack' argument contains the stack trace.
/// The callback is invoked after the information is printed to the console, and
/// could be used to print additional information, such as from
/// [debugDumpApp()].
WidgetsExceptionHandler debugWidgetsExceptionHandler;
void _debugReportException(String context, dynamic exception, StackTrace stack) { void _debugReportException(String context, dynamic exception, StackTrace stack) {
print('------------------------------------------------------------------------'); print('------------------------------------------------------------------------');
'Exception caught while $context'.split('\n').forEach(print); 'Exception caught while $context'.split('\n').forEach(print);
...@@ -1663,7 +1673,7 @@ void _debugReportException(String context, dynamic exception, StackTrace stack) ...@@ -1663,7 +1673,7 @@ void _debugReportException(String context, dynamic exception, StackTrace stack)
'$stack'.split('\n').forEach(print); '$stack'.split('\n').forEach(print);
print('Build stack:'); print('Build stack:');
Component._debugComponentBuildTree.forEach((Component component) { print(' $component'); }); Component._debugComponentBuildTree.forEach((Component component) { print(' $component'); });
print('Current application widget tree:'); if (debugWidgetsExceptionHandler != null)
debugDumpApp(); debugWidgetsExceptionHandler(context, exception, stack);
print('------------------------------------------------------------------------'); print('------------------------------------------------------------------------');
} }
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