Commit 12054e33 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Clean up some of the fn3 debugging logic. (#6024)

The debugging logic was lagging behind the recent actual logic changes,
especially around buildScope.
parent fea4a91a
...@@ -1607,7 +1607,7 @@ class BuildOwner { ...@@ -1607,7 +1607,7 @@ class BuildOwner {
/// Only one [buildScope] can be active at a time. /// Only one [buildScope] can be active at a time.
/// ///
/// A [buildScope] implies a [lockState] scope as well. /// A [buildScope] implies a [lockState] scope as well.
void buildScope(Element context, [VoidCallback callback]) { void buildScope(BuildableElement context, [VoidCallback callback]) {
if (callback == null && _dirtyElements.isEmpty) if (callback == null && _dirtyElements.isEmpty)
return; return;
assert(context != null); assert(context != null);
...@@ -1623,8 +1623,27 @@ class BuildOwner { ...@@ -1623,8 +1623,27 @@ class BuildOwner {
Timeline.startSync('Build'); Timeline.startSync('Build');
try { try {
_scheduledFlushDirtyElements = true; _scheduledFlushDirtyElements = true;
if (callback != null) if (callback != null) {
assert(context is BuildableElement);
assert(_debugStateLocked);
BuildableElement debugPreviousBuildTarget;
assert(() {
context._debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
debugPreviousBuildTarget = _debugCurrentBuildTarget;
_debugCurrentBuildTarget = context;
return true;
});
try {
callback(); callback();
} finally {
assert(() {
context._debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
assert(_debugCurrentBuildTarget == context);
_debugCurrentBuildTarget = debugPreviousBuildTarget;
return true;
});
}
}
_dirtyElements.sort(_elementSort); _dirtyElements.sort(_elementSort);
_dirtyElementsNeedsResorting = false; _dirtyElementsNeedsResorting = false;
int dirtyCount = _dirtyElements.length; int dirtyCount = _dirtyElements.length;
...@@ -2423,6 +2442,10 @@ class ErrorWidget extends LeafRenderObjectWidget { ...@@ -2423,6 +2442,10 @@ class ErrorWidget extends LeafRenderObjectWidget {
} }
/// An [Element] that can be marked dirty and rebuilt. /// An [Element] that can be marked dirty and rebuilt.
///
/// In practice, all subclasses of [Element] in the Flutter framework are
/// subclasses of [BuildableElement]. The distinction exists primarily to
/// segregate unrelated code.
abstract class BuildableElement extends Element { abstract class BuildableElement extends Element {
/// Creates an element that uses the given widget as its configuration. /// Creates an element that uses the given widget as its configuration.
BuildableElement(Widget widget) : super(widget); BuildableElement(Widget widget) : super(widget);
...@@ -2464,26 +2487,34 @@ abstract class BuildableElement extends Element { ...@@ -2464,26 +2487,34 @@ abstract class BuildableElement extends Element {
assert(_debugLifecycleState == _ElementLifecycle.active); assert(_debugLifecycleState == _ElementLifecycle.active);
assert(() { assert(() {
if (owner._debugBuilding) { if (owner._debugBuilding) {
if (owner._debugCurrentBuildTarget == null) { assert(owner._debugCurrentBuildTarget != null);
// If _debugCurrentBuildTarget is null, we're not actually building a assert(owner._debugStateLocked);
// widget but instead building the root of the tree via runApp.
// TODO(abarth): Remove these cases and ensure that we always have
// a current build target when we're building.
return true;
}
if (_debugIsInScope(owner._debugCurrentBuildTarget)) if (_debugIsInScope(owner._debugCurrentBuildTarget))
return true; return true;
} if (!_debugAllowIgnoredCallsToMarkNeedsBuild) {
if (owner._debugStateLocked && (!_debugAllowIgnoredCallsToMarkNeedsBuild || !dirty)) {
throw new FlutterError( throw new FlutterError(
'setState() or markNeedsBuild() called during build.\n' 'setState() or markNeedsBuild() called during build.\n'
'This widget cannot be marked as needing to build because the framework ' 'This ${widget.runtimeType} widget cannot be marked as needing to build because the framework '
'is already in the process of building widgets. A widget can be marked as ' 'is already in the process of building widgets. A widget can be marked as '
'needing to be built during the build phase only if one if its ancestors ' 'needing to be built during the build phase only if one of its ancestors '
'is currently building. This exception is allowed because the framework ' 'is currently building. This exception is allowed because the framework '
'builds parent widgets before children, which means a dirty descendant ' 'builds parent widgets before children, which means a dirty descendant '
'will always be built. Otherwise, the framework might not visit this ' 'will always be built. Otherwise, the framework might not visit this '
'widget during this build phase.' 'widget during this build phase.\n'
'The widget on which setState() or markNeedsBuild() was called was:\n'
' $this\n'
'${owner._debugCurrentBuildTarget == null ? "" : "The widget which was currently being built when the offending call was made was:\n ${owner._debugCurrentBuildTarget}"}'
);
}
assert(dirty); // can only get here if we're not in scope, but ignored calls are allowed, and our call would somehow be ignored (since we're already dirty)
} else if (owner._debugStateLocked) {
assert(!_debugAllowIgnoredCallsToMarkNeedsBuild);
throw new FlutterError(
'setState() or markNeedsBuild() called when widget tree was locked.\n'
'This ${widget.runtimeType} widget cannot be marked as needing to build '
'because the framework is locked.\n'
'The widget on which setState() or markNeedsBuild() was called was:\n'
' $this\n'
); );
} }
return true; return true;
...@@ -2596,6 +2627,8 @@ Widget _buildNothing(BuildContext context) => null; ...@@ -2596,6 +2627,8 @@ Widget _buildNothing(BuildContext context) => null;
/// ///
/// Rather than creating a [RenderObject] directly, a [ComponentElement] creates /// Rather than creating a [RenderObject] directly, a [ComponentElement] creates
/// [RenderObject]s indirectly by creating other [Element]s. /// [RenderObject]s indirectly by creating other [Element]s.
///
/// Contrast with [RenderObjectElement].
abstract class ComponentElement extends BuildableElement { abstract class ComponentElement extends BuildableElement {
/// Creates an element that uses the given widget as its configuration. /// Creates an element that uses the given widget as its configuration.
ComponentElement(Widget widget) : super(widget); ComponentElement(Widget widget) : super(widget);
...@@ -2994,6 +3027,12 @@ class InheritedElement extends ProxyElement { ...@@ -2994,6 +3027,12 @@ class InheritedElement extends ProxyElement {
} }
/// An element that uses a [RenderObjectWidget] as its configuration. /// An element that uses a [RenderObjectWidget] as its configuration.
///
/// [RenderObjectElement] objects have an associated [RenderObject] widget in
/// the render tree, which handles concrete operations like laying out,
/// painting, and hit testing.
///
/// Contrast with [ComponentElement].
abstract class RenderObjectElement extends BuildableElement { abstract class RenderObjectElement extends BuildableElement {
/// Creates an element that uses the given widget as its configuration. /// Creates an element that uses the given widget as its configuration.
RenderObjectElement(RenderObjectWidget widget) : super(widget); RenderObjectElement(RenderObjectWidget widget) : super(widget);
......
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