Skip to content

Commit

Permalink
Provide hooks for when exceptions are thrown.
Browse files Browse the repository at this point in the history
This might be helpful for #1219.

Also, remove inDebugMode since it's redundant with just using asserts,
which compile entirely out in release mode.
  • Loading branch information
Hixie committed Sep 18, 2015
1 parent 4c5e81c commit cbb6e05
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 37 deletions.
40 changes: 24 additions & 16 deletions sky/packages/sky/lib/src/rendering/box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -444,28 +444,36 @@ abstract class RenderBox extends RenderObject {
/// of those functins, call [markNeedsLayout] instead to schedule a layout of
/// the box.
Size get size {
if (_size is _DebugSize) {
final _DebugSize _size = this._size; // TODO(ianh): Remove this once the analyzer is cleverer
assert(_size._owner == this);
if (RenderObject.debugActiveLayout != null) {
// we are always allowed to access our own size (for print debugging and asserts if nothing else)
// other than us, the only object that's allowed to read our size is our parent, if they're said they will
// if you hit this assert trying to access a child's size, pass parentUsesSize: true in layout()
assert(debugDoingThisResize || debugDoingThisLayout ||
(RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent));
assert(() {
if (_size is _DebugSize) {
final _DebugSize _size = this._size; // TODO(ianh): Remove this once the analyzer is cleverer
assert(_size._owner == this);
if (RenderObject.debugActiveLayout != null) {
// we are always allowed to access our own size (for print debugging and asserts if nothing else)
// other than us, the only object that's allowed to read our size is our parent, if they're said they will
// if you hit this assert trying to access a child's size, pass parentUsesSize: true in layout()
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;
}
void set size(Size value) {
assert((sizedByParent && debugDoingThisResize) ||
(!sizedByParent && debugDoingThisLayout));
if (value is _DebugSize) {
assert(value._canBeUsedByParent);
assert(value._owner.parent == this);
}
_size = inDebugBuild ? new _DebugSize(value, this, debugCanParentUseSize) : value;
assert(() {
if (value is _DebugSize)
return value._canBeUsedByParent && value._owner.parent == this;
return true;
});
_size = value;
assert(() {
_size = new _DebugSize(_size, this, debugCanParentUseSize);
return true;
});
assert(debugDoesMeetConstraints());
}

Expand Down
16 changes: 0 additions & 16 deletions sky/packages/sky/lib/src/rendering/debug.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,6 @@

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.
bool debugPaintSizeEnabled = false;

Expand All @@ -43,6 +30,3 @@ bool debugPaintBoundsEnabled = false;

/// The color to use when painting RenderError boxes in checked mode.
sky.Color debugErrorBoxColor = const sky.Color(0xFFFF0000);

/// How many lines of debugging output to include when an exception is reported.
int debugRenderObjectDumpMaxLength = 10;
18 changes: 15 additions & 3 deletions sky/packages/sky/lib/src/rendering/object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,17 @@ typedef void RenderObjectVisitor(RenderObject child);
typedef void LayoutCallback(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
///
/// Render objects have a reference to their parent but do not commit to a model
Expand Down Expand Up @@ -445,10 +456,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
print('$exception');
print('Stack trace:');
print('$stack');
'The following RenderObject was being processed when the exception was fired (limited to $debugRenderObjectDumpMaxLength lines):\n${this}'
.split('\n').take(debugRenderObjectDumpMaxLength+1).forEach(print);
print('The following RenderObject was being processed when the exception was fired:\n${this}');
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;
Expand Down
14 changes: 12 additions & 2 deletions sky/packages/sky/lib/src/widgets/framework.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,16 @@ class ErrorWidget extends LeafRenderObjectWrapper {
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) {
print('------------------------------------------------------------------------');
'Exception caught while $context'.split('\n').forEach(print);
Expand All @@ -1663,7 +1673,7 @@ void _debugReportException(String context, dynamic exception, StackTrace stack)
'$stack'.split('\n').forEach(print);
print('Build stack:');
Component._debugComponentBuildTree.forEach((Component component) { print(' $component'); });
print('Current application widget tree:');
debugDumpApp();
if (debugWidgetsExceptionHandler != null)
debugWidgetsExceptionHandler(context, exception, stack);
print('------------------------------------------------------------------------');
}

0 comments on commit cbb6e05

Please sign in to comment.