Unverified Commit 10bcddcc authored by Jacob Richman's avatar Jacob Richman Committed by GitHub

Add option to track widget rebuilds and repaints from the Flutter inspector. (#23534)

parent b722a744
......@@ -5,6 +5,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import 'object.dart';
export 'package:flutter/foundation.dart' show debugPrint;
// Any changes to this file should be reflected in the debugAssertAllRenderVarsUnset()
......@@ -116,6 +118,25 @@ bool debugCheckIntrinsicSizes = false;
/// areas are being excessively repainted.
bool debugProfilePaintsEnabled = false;
/// Signature for [debugOnProfilePaint] implementations.
typedef ProfilePaintCallback = void Function(RenderObject renderObject);
/// Callback invoked for every [RenderObject] painted each frame.
///
/// This callback is only invoked in debug builds.
///
/// See also:
///
/// * [debugProfilePaintsEnabled], which does something similar but adds
/// [dart:developer.Timeline] events instead of invoking a callback.
/// * [debugOnRebuildDirtyWidget], which does something similar for widgets
/// being built.
/// * [WidgetInspectorService], which uses the [debugOnProfilePaint]
/// callback to generate aggregate profile statistics describing what paints
/// occurred when the `ext.flutter.inspector.trackRepaintWidgets` service
/// extension is enabled.
ProfilePaintCallback debugOnProfilePaint;
/// Setting to true will cause all clipping effects from the layer tree to be
/// ignored.
///
......@@ -205,7 +226,8 @@ bool debugAssertAllRenderVarsUnset(String reason, { bool debugCheckIntrinsicSize
debugPrintMarkNeedsPaintStacks ||
debugPrintLayouts ||
debugCheckIntrinsicSizes != debugCheckIntrinsicSizesOverride ||
debugProfilePaintsEnabled) {
debugProfilePaintsEnabled ||
debugOnProfilePaint != null) {
throw FlutterError(reason);
}
return true;
......
......@@ -161,6 +161,8 @@ class PaintingContext extends ClipContext {
assert(() {
if (debugProfilePaintsEnabled)
Timeline.startSync('${child.runtimeType}', arguments: timelineWhitelistArguments);
if (debugOnProfilePaint != null)
debugOnProfilePaint(child);
return true;
}());
......
......@@ -711,6 +711,11 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
@override
Future<void> performReassemble() {
assert(() {
WidgetInspectorService.instance.performReassemble();
return true;
}());
deferFirstFrameReport();
if (renderViewElement != null)
buildOwner.reassemble(renderViewElement);
......
......@@ -30,6 +30,26 @@ import 'table.dart';
/// See also the discussion at [WidgetsBinding.drawFrame].
bool debugPrintRebuildDirtyWidgets = false;
/// Signature for [debugOnRebuildDirtyWidget] implementations.
typedef RebuildDirtyWidgetCallback = void Function(Element e, bool builtOnce);
/// Callback invoked for every dirty widget built each frame.
///
/// This callback is only invoked in debug builds.
///
/// See also:
///
/// * [debugPrintRebuildDirtyWidgets], which does something similar but logs
/// to the console instead of invoking a callback.
/// * [debugOnProfilePaint], which does something similar for [RenderObject]
/// painting.
/// * [WidgetInspectorService], which uses the [debugOnRebuildDirtyWidget]
/// callback to generate aggregate profile statistics describing which widget
/// rebuilds occurred when the
/// `ext.flutter.inspector.trackRebuildDirtyWidgets` service extension is
/// enabled.
RebuildDirtyWidgetCallback debugOnRebuildDirtyWidget;
/// Log all calls to [BuildOwner.buildScope].
///
/// Combined with [debugPrintScheduleBuildForStacks], this allows you to track
......
......@@ -3514,6 +3514,9 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
if (!_active || !_dirty)
return;
assert(() {
if (debugOnRebuildDirtyWidget != null) {
debugOnRebuildDirtyWidget(this, _debugBuiltOnce);
}
if (debugPrintRebuildDirtyWidgets) {
if (!_debugBuiltOnce) {
debugPrint('Building $this');
......
......@@ -528,12 +528,18 @@ void main() {
});
test('Service extensions - posttest', () async {
// See widget_inspector_test.dart for tests of the 15 ext.flutter.inspector
// See widget_inspector_test.dart for tests of the ext.flutter.inspector
// service extensions included in this count.
int widgetInspectorExtensionCount = 15;
if (WidgetInspectorService.instance.isWidgetCreationTracked()) {
// Some inspector extensions are only exposed if widget creation locations
// are tracked.
widgetInspectorExtensionCount += 2;
}
// If you add a service extension... TEST IT! :-)
// ...then increment this number.
expect(binding.extensions.length, 38);
expect(binding.extensions.length, 23 + widgetInspectorExtensionCount);
expect(console, isEmpty);
debugPrint = debugPrintThrottled;
......
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