Unverified Commit a2e25749 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Remove the fast reassemble / single widget reload feature (#132255)

Fixes https://github.com/flutter/flutter/issues/132157
parent 6cf5dbe3
...@@ -168,13 +168,6 @@ abstract class BindingBase { ...@@ -168,13 +168,6 @@ abstract class BindingBase {
static Type? _debugInitializedType; static Type? _debugInitializedType;
static bool _debugServiceExtensionsRegistered = false; static bool _debugServiceExtensionsRegistered = false;
/// Additional configuration used by the framework during hot reload.
///
/// See also:
///
/// * [DebugReassembleConfig], which describes the configuration.
static DebugReassembleConfig? debugReassembleConfig;
/// Deprecated. Will be removed in a future version of Flutter. /// Deprecated. Will be removed in a future version of Flutter.
/// ///
/// This property has been deprecated to prepare for Flutter's upcoming /// This property has been deprecated to prepare for Flutter's upcoming
...@@ -989,23 +982,3 @@ abstract class BindingBase { ...@@ -989,23 +982,3 @@ abstract class BindingBase {
Future<void> _exitApplication() async { Future<void> _exitApplication() async {
exit(0); exit(0);
} }
/// Additional configuration used for hot reload reassemble optimizations.
///
/// Do not extend, implement, or mixin this class. This may only be instantiated
/// in debug mode.
class DebugReassembleConfig {
/// Create a new [DebugReassembleConfig].
///
/// Throws a [FlutterError] if this is called in profile or release mode.
DebugReassembleConfig({
this.widgetName,
}) {
if (!kDebugMode) {
throw FlutterError('Cannot instantiate DebugReassembleConfig in profile or release mode.');
}
}
/// The name of the widget that was modified, or `null` if the change was elsewhere.
final String? widgetName;
}
...@@ -603,7 +603,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture ...@@ -603,7 +603,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
@override @override
Future<void> performReassemble() async { Future<void> performReassemble() async {
await super.performReassemble(); await super.performReassemble();
if (BindingBase.debugReassembleConfig?.widgetName == null) {
if (!kReleaseMode) { if (!kReleaseMode) {
FlutterTimeline.startSync('Preparing Hot Reload (layout)'); FlutterTimeline.startSync('Preparing Hot Reload (layout)');
} }
...@@ -616,7 +615,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture ...@@ -616,7 +615,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
FlutterTimeline.finishSync(); FlutterTimeline.finishSync();
} }
} }
}
scheduleWarmUpFrame(); scheduleWarmUpFrame();
await endOfFrame; await endOfFrame;
} }
......
...@@ -505,23 +505,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB ...@@ -505,23 +505,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}, },
); );
registerServiceExtension(
name: WidgetsServiceExtensions.fastReassemble.name,
callback: (Map<String, Object> params) async {
// This mirrors the implementation of the 'reassemble' callback registration
// in lib/src/foundation/binding.dart, but with the extra binding config used
// to skip some reassemble work.
final String? className = params['className'] as String?;
BindingBase.debugReassembleConfig = DebugReassembleConfig(widgetName: className);
try {
await reassembleApplication();
} finally {
BindingBase.debugReassembleConfig = null;
}
return <String, String>{'type': 'Success'};
},
);
// Expose the ability to send Widget rebuilds as [Timeline] events. // Expose the ability to send Widget rebuilds as [Timeline] events.
registerBoolServiceExtension( registerBoolServiceExtension(
name: WidgetsServiceExtensions.profileWidgetBuilds.name, name: WidgetsServiceExtensions.profileWidgetBuilds.name,
...@@ -560,7 +543,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB ...@@ -560,7 +543,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
Future<void> _forceRebuild() { Future<void> _forceRebuild() {
if (rootElement != null) { if (rootElement != null) {
buildOwner!.reassemble(rootElement!, null); buildOwner!.reassemble(rootElement!);
return endOfFrame; return endOfFrame;
} }
return Future<void>.value(); return Future<void>.value();
...@@ -1090,7 +1073,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB ...@@ -1090,7 +1073,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
}()); }());
if (rootElement != null) { if (rootElement != null) {
buildOwner!.reassemble(rootElement!, BindingBase.debugReassembleConfig); buildOwner!.reassemble(rootElement!);
} }
return super.performReassemble(); return super.performReassemble();
} }
......
...@@ -3252,14 +3252,13 @@ class BuildOwner { ...@@ -3252,14 +3252,13 @@ class BuildOwner {
/// changed implementations. /// changed implementations.
/// ///
/// This is expensive and should not be called except during development. /// This is expensive and should not be called except during development.
void reassemble(Element root, DebugReassembleConfig? reassembleConfig) { void reassemble(Element root) {
if (!kReleaseMode) { if (!kReleaseMode) {
FlutterTimeline.startSync('Preparing Hot Reload (widgets)'); FlutterTimeline.startSync('Preparing Hot Reload (widgets)');
} }
try { try {
assert(root._parent == null); assert(root._parent == null);
assert(root.owner == this); assert(root.owner == this);
root._debugReassembleConfig = reassembleConfig;
root.reassemble(); root.reassemble();
} finally { } finally {
if (!kReleaseMode) { if (!kReleaseMode) {
...@@ -3374,7 +3373,6 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -3374,7 +3373,6 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
} }
Element? _parent; Element? _parent;
DebugReassembleConfig? _debugReassembleConfig;
_NotificationNode? _notificationTree; _NotificationNode? _notificationTree;
/// Compare two widgets for equality. /// Compare two widgets for equality.
...@@ -3526,15 +3524,10 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -3526,15 +3524,10 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
@mustCallSuper @mustCallSuper
@protected @protected
void reassemble() { void reassemble() {
if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
markNeedsBuild(); markNeedsBuild();
_debugReassembleConfig = null;
}
visitChildren((Element child) { visitChildren((Element child) {
child._debugReassembleConfig = _debugReassembleConfig;
child.reassemble(); child.reassemble();
}); });
_debugReassembleConfig = null;
} }
bool _debugIsInScope(Element target) { bool _debugIsInScope(Element target) {
...@@ -5585,9 +5578,7 @@ class StatefulElement extends ComponentElement { ...@@ -5585,9 +5578,7 @@ class StatefulElement extends ComponentElement {
@override @override
void reassemble() { void reassemble() {
if (_debugShouldReassemble(_debugReassembleConfig, _widget)) {
state.reassemble(); state.reassemble();
}
super.reassemble(); super.reassemble();
} }
...@@ -6952,9 +6943,3 @@ class _NullWidget extends Widget { ...@@ -6952,9 +6943,3 @@ class _NullWidget extends Widget {
@override @override
Element createElement() => throw UnimplementedError(); Element createElement() => throw UnimplementedError();
} }
// Whether a [DebugReassembleConfig] indicates that an element holding [widget] can skip
// a reassemble.
bool _debugShouldReassemble(DebugReassembleConfig? config, Widget? widget) {
return config == null || config.widgetName == null || widget?.runtimeType.toString() == config.widgetName;
}
...@@ -970,7 +970,7 @@ mixin WidgetInspectorService { ...@@ -970,7 +970,7 @@ mixin WidgetInspectorService {
Future<void> forceRebuild() { Future<void> forceRebuild() {
final WidgetsBinding binding = WidgetsBinding.instance; final WidgetsBinding binding = WidgetsBinding.instance;
if (binding.rootElement != null) { if (binding.rootElement != null) {
binding.buildOwner!.reassemble(binding.rootElement!, null); binding.buildOwner!.reassemble(binding.rootElement!);
return binding.endOfFrame; return binding.endOfFrame;
} }
return Future<void>.value(); return Future<void>.value();
......
...@@ -116,6 +116,7 @@ Future<Map<String, dynamic>> hasReassemble(Future<Map<String, dynamic>> pendingR ...@@ -116,6 +116,7 @@ Future<Map<String, dynamic>> hasReassemble(Future<Map<String, dynamic>> pendingR
} }
void main() { void main() {
final Set<String> testedExtensions = <String>{}; // Add the name of an extension to this set in the test where it is tested.
final List<String?> console = <String?>[]; final List<String?> console = <String?>[];
late PipelineOwner owner; late PipelineOwner owner;
...@@ -153,6 +154,9 @@ void main() { ...@@ -153,6 +154,9 @@ void main() {
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(WidgetsServiceExtensions.didSendFirstFrameEvent.name);
testedExtensions.add(WidgetsServiceExtensions.didSendFirstFrameRasterizedEvent.name);
expect(debugPrint, equals(debugPrintThrottled)); expect(debugPrint, equals(debugPrintThrottled));
debugPrint = (String? message, { int? wrapWidth }) { debugPrint = (String? message, { int? wrapWidth }) {
console.add(message); console.add(message);
...@@ -162,12 +166,13 @@ void main() { ...@@ -162,12 +166,13 @@ void main() {
tearDownAll(() async { tearDownAll(() async {
// See widget_inspector_test.dart for tests of the ext.flutter.inspector // See widget_inspector_test.dart for tests of the ext.flutter.inspector
// service extensions included in this count. // service extensions included in this count.
int widgetInspectorExtensionCount = 20; int widgetInspectorExtensionCount = 28;
if (WidgetInspectorService.instance.isWidgetCreationTracked()) { if (WidgetInspectorService.instance.isWidgetCreationTracked()) {
// Some inspector extensions are only exposed if widget creation locations // Some inspector extensions are only exposed if widget creation locations
// are tracked. // are tracked.
widgetInspectorExtensionCount += 2; widgetInspectorExtensionCount += 2;
} }
expect(binding.extensions.keys.where((String name) => name.startsWith('inspector.')), hasLength(widgetInspectorExtensionCount));
// The following service extensions are disabled in web: // The following service extensions are disabled in web:
// 1. exit // 1. exit
...@@ -175,12 +180,13 @@ void main() { ...@@ -175,12 +180,13 @@ void main() {
const int disabledExtensions = kIsWeb ? 2 : 0; const int disabledExtensions = kIsWeb ? 2 : 0;
// The expected number of registered service extensions in the Flutter // The expected number of registered service extensions in the Flutter
// framework, excluding any that are for the widget inspector // framework, excluding any that are for the widget inspector (see
// (see widget_inspector_test.dart for tests of the ext.flutter.inspector // widget_inspector_test.dart for tests of the ext.flutter.inspector service
// service extensions). // extensions). Any test counted here must be tested in this file!
const int serviceExtensionCount = 38; const int serviceExtensionCount = 29;
expect(binding.extensions.length, serviceExtensionCount + widgetInspectorExtensionCount - disabledExtensions); expect(binding.extensions.length, serviceExtensionCount + widgetInspectorExtensionCount - disabledExtensions);
expect(testedExtensions, hasLength(serviceExtensionCount));
expect(console, isEmpty); expect(console, isEmpty);
debugPrint = debugPrintThrottled; debugPrint = debugPrintThrottled;
...@@ -213,6 +219,8 @@ void main() { ...@@ -213,6 +219,8 @@ void main() {
expect(result, <String, String>{'enabled': 'true'}); expect(result, <String, String>{'enabled': 'true'});
expect(WidgetsApp.debugAllowBannerOverride, true); expect(WidgetsApp.debugAllowBannerOverride, true);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(WidgetsServiceExtensions.debugAllowBanner.name);
}); });
test('Service extensions - debugDumpApp', () async { test('Service extensions - debugDumpApp', () async {
...@@ -221,6 +229,8 @@ void main() { ...@@ -221,6 +229,8 @@ void main() {
expect(result, <String, dynamic>{ expect(result, <String, dynamic>{
'data': matches('TestServiceExtensionsBinding - DEBUG MODE\n<no tree currently mounted>'), 'data': matches('TestServiceExtensionsBinding - DEBUG MODE\n<no tree currently mounted>'),
}); });
testedExtensions.add(WidgetsServiceExtensions.debugDumpApp.name);
}); });
test('Service extensions - debugDumpFocusTree', () async { test('Service extensions - debugDumpFocusTree', () async {
...@@ -234,6 +244,8 @@ void main() { ...@@ -234,6 +244,8 @@ void main() {
r'$', r'$',
), ),
}); });
testedExtensions.add(WidgetsServiceExtensions.debugDumpFocusTree.name);
}); });
test('Service extensions - debugDumpRenderTree', () async { test('Service extensions - debugDumpRenderTree', () async {
...@@ -251,6 +263,8 @@ void main() { ...@@ -251,6 +263,8 @@ void main() {
r'$', r'$',
), ),
}); });
testedExtensions.add(RenderingServiceExtensions.debugDumpRenderTree.name);
}); });
test('Service extensions - debugDumpLayerTree', () async { test('Service extensions - debugDumpLayerTree', () async {
...@@ -274,6 +288,8 @@ void main() { ...@@ -274,6 +288,8 @@ void main() {
r'$', r'$',
), ),
}); });
testedExtensions.add(RenderingServiceExtensions.debugDumpLayerTree.name);
}); });
test('Service extensions - debugDumpSemanticsTreeInTraversalOrder', () async { test('Service extensions - debugDumpSemanticsTreeInTraversalOrder', () async {
...@@ -288,6 +304,8 @@ void main() { ...@@ -288,6 +304,8 @@ void main() {
r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.' r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.'
) )
}); });
testedExtensions.add(RenderingServiceExtensions.debugDumpSemanticsTreeInTraversalOrder.name);
}); });
test('Service extensions - debugDumpSemanticsTreeInInverseHitTestOrder', () async { test('Service extensions - debugDumpSemanticsTreeInInverseHitTestOrder', () async {
...@@ -302,10 +320,12 @@ void main() { ...@@ -302,10 +320,12 @@ void main() {
r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.' r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.'
) )
}); });
testedExtensions.add(RenderingServiceExtensions.debugDumpSemanticsTreeInInverseHitTestOrder.name);
}); });
test('Service extensions - debugPaint', () async { test('Service extensions - debugPaint', () async {
final Iterable<Map<String, dynamic>> extensionChangedEvents = binding.getServiceExtensionStateChangedEvents('ext.flutter.debugPaint'); final Iterable<Map<String, dynamic>> extensionChangedEvents = binding.getServiceExtensionStateChangedEvents('ext.flutter.${RenderingServiceExtensions.debugPaint.name}');
Map<String, dynamic> extensionChangedEvent; Map<String, dynamic> extensionChangedEvent;
Map<String, dynamic> result; Map<String, dynamic> result;
Future<Map<String, dynamic>> pendingResult; Future<Map<String, dynamic>> pendingResult;
...@@ -357,6 +377,8 @@ void main() { ...@@ -357,6 +377,8 @@ void main() {
expect(debugPaintSizeEnabled, false); expect(debugPaintSizeEnabled, false);
expect(extensionChangedEvents.length, 2); expect(extensionChangedEvents.length, 2);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.debugPaint.name);
}); });
test('Service extensions - debugPaintBaselinesEnabled', () async { test('Service extensions - debugPaintBaselinesEnabled', () async {
...@@ -399,6 +421,8 @@ void main() { ...@@ -399,6 +421,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(debugPaintBaselinesEnabled, false); expect(debugPaintBaselinesEnabled, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.debugPaintBaselinesEnabled.name);
}); });
test('Service extensions - invertOversizedImages', () async { test('Service extensions - invertOversizedImages', () async {
...@@ -445,6 +469,8 @@ void main() { ...@@ -445,6 +469,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(debugInvertOversizedImages, false); expect(debugInvertOversizedImages, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.invertOversizedImages.name);
}); });
test('Service extensions - profileWidgetBuilds', () async { test('Service extensions - profileWidgetBuilds', () async {
...@@ -474,6 +500,8 @@ void main() { ...@@ -474,6 +500,8 @@ void main() {
expect(debugProfileBuildsEnabled, false); expect(debugProfileBuildsEnabled, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(WidgetsServiceExtensions.profileWidgetBuilds.name);
}); });
test('Service extensions - profileUserWidgetBuilds', () async { test('Service extensions - profileUserWidgetBuilds', () async {
...@@ -503,6 +531,8 @@ void main() { ...@@ -503,6 +531,8 @@ void main() {
expect(debugProfileBuildsEnabledUserWidgets, false); expect(debugProfileBuildsEnabledUserWidgets, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(WidgetsServiceExtensions.profileUserWidgetBuilds.name);
}); });
test('Service extensions - profileRenderObjectPaints', () async { test('Service extensions - profileRenderObjectPaints', () async {
...@@ -532,6 +562,8 @@ void main() { ...@@ -532,6 +562,8 @@ void main() {
expect(debugProfilePaintsEnabled, false); expect(debugProfilePaintsEnabled, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.profileRenderObjectPaints.name);
}); });
test('Service extensions - profileRenderObjectLayouts', () async { test('Service extensions - profileRenderObjectLayouts', () async {
...@@ -561,6 +593,8 @@ void main() { ...@@ -561,6 +593,8 @@ void main() {
expect(debugProfileLayoutsEnabled, false); expect(debugProfileLayoutsEnabled, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.profileRenderObjectLayouts.name);
}); });
test('Service extensions - evict', () async { test('Service extensions - evict', () async {
...@@ -596,12 +630,16 @@ void main() { ...@@ -596,12 +630,16 @@ void main() {
expect(data, isFalse); expect(data, isFalse);
expect(completed, isTrue); expect(completed, isTrue);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
testedExtensions.add(ServicesServiceExtensions.evict.name);
}); });
test('Service extensions - exit', () async { test('Service extensions - exit', () async {
// no test for _calling_ 'exit', because that should terminate the process! // no test for _calling_ 'exit', because that should terminate the process!
// Not expecting extension to be available for web platform. // Not expecting extension to be available for web platform.
expect(binding.extensions.containsKey(FoundationServiceExtensions.exit.name), !isBrowser); expect(binding.extensions.containsKey(FoundationServiceExtensions.exit.name), !isBrowser);
testedExtensions.add(FoundationServiceExtensions.exit.name);
}); });
test('Service extensions - platformOverride', () async { test('Service extensions - platformOverride', () async {
...@@ -688,6 +726,8 @@ void main() { ...@@ -688,6 +726,8 @@ void main() {
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'android'); expect(extensionChangedEvent['value'], 'android');
binding.reassembled = 0; binding.reassembled = 0;
testedExtensions.add(FoundationServiceExtensions.platformOverride.name);
}); });
test('Service extensions - repaintRainbow', () async { test('Service extensions - repaintRainbow', () async {
...@@ -731,6 +771,8 @@ void main() { ...@@ -731,6 +771,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(debugRepaintRainbowEnabled, false); expect(debugRepaintRainbowEnabled, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.repaintRainbow.name);
}); });
test('Service extensions - debugDisableClipLayers', () async { test('Service extensions - debugDisableClipLayers', () async {
...@@ -773,6 +815,8 @@ void main() { ...@@ -773,6 +815,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(debugDisableClipLayers, false); expect(debugDisableClipLayers, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.debugDisableClipLayers.name);
}); });
test('Service extensions - debugDisablePhysicalShapeLayers', () async { test('Service extensions - debugDisablePhysicalShapeLayers', () async {
...@@ -815,6 +859,8 @@ void main() { ...@@ -815,6 +859,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(debugDisablePhysicalShapeLayers, false); expect(debugDisablePhysicalShapeLayers, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.debugDisablePhysicalShapeLayers.name);
}); });
test('Service extensions - debugDisableOpacityLayers', () async { test('Service extensions - debugDisableOpacityLayers', () async {
...@@ -857,6 +903,8 @@ void main() { ...@@ -857,6 +903,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(debugDisableOpacityLayers, false); expect(debugDisableOpacityLayers, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(RenderingServiceExtensions.debugDisableOpacityLayers.name);
}); });
test('Service extensions - reassemble', () async { test('Service extensions - reassemble', () async {
...@@ -880,6 +928,8 @@ void main() { ...@@ -880,6 +928,8 @@ void main() {
expect(result, <String, String>{}); expect(result, <String, String>{});
expect(binding.reassembled, 1); expect(binding.reassembled, 1);
binding.reassembled = 0; binding.reassembled = 0;
testedExtensions.add(FoundationServiceExtensions.reassemble.name);
}); });
test('Service extensions - showPerformanceOverlay', () async { test('Service extensions - showPerformanceOverlay', () async {
...@@ -888,6 +938,7 @@ void main() { ...@@ -888,6 +938,7 @@ void main() {
// The performance overlay service extension is disabled on the web. // The performance overlay service extension is disabled on the web.
if (kIsWeb) { if (kIsWeb) {
expect(binding.extensions.containsKey(WidgetsServiceExtensions.showPerformanceOverlay.name), isFalse); expect(binding.extensions.containsKey(WidgetsServiceExtensions.showPerformanceOverlay.name), isFalse);
testedExtensions.add(WidgetsServiceExtensions.showPerformanceOverlay.name);
return; return;
} }
...@@ -909,6 +960,8 @@ void main() { ...@@ -909,6 +960,8 @@ void main() {
expect(result, <String, String>{'enabled': 'false'}); expect(result, <String, String>{'enabled': 'false'});
expect(WidgetsApp.showPerformanceOverlayOverride, false); expect(WidgetsApp.showPerformanceOverlayOverride, false);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(WidgetsServiceExtensions.showPerformanceOverlay.name);
}); });
test('Service extensions - timeDilation', () async { test('Service extensions - timeDilation', () async {
...@@ -945,6 +998,8 @@ void main() { ...@@ -945,6 +998,8 @@ void main() {
expect(timeDilation, 1.0); expect(timeDilation, 1.0);
expect(extensionChangedEvents.length, 2); expect(extensionChangedEvents.length, 2);
expect(binding.frameScheduled, isFalse); expect(binding.frameScheduled, isFalse);
testedExtensions.add(SchedulerServiceExtensions.timeDilation.name);
}); });
test('Service extensions - brightnessOverride', () async { test('Service extensions - brightnessOverride', () async {
...@@ -953,6 +1008,8 @@ void main() { ...@@ -953,6 +1008,8 @@ void main() {
final String brightnessValue = result['value'] as String; final String brightnessValue = result['value'] as String;
expect(brightnessValue, 'Brightness.light'); expect(brightnessValue, 'Brightness.light');
testedExtensions.add(FoundationServiceExtensions.brightnessOverride.name);
}); });
test('Service extensions - activeDevToolsServerAddress', () async { test('Service extensions - activeDevToolsServerAddress', () async {
...@@ -966,6 +1023,8 @@ void main() { ...@@ -966,6 +1023,8 @@ void main() {
result = await binding.testExtension(FoundationServiceExtensions.activeDevToolsServerAddress.name, <String, String>{'value': 'http://127.0.0.1:9102'}); result = await binding.testExtension(FoundationServiceExtensions.activeDevToolsServerAddress.name, <String, String>{'value': 'http://127.0.0.1:9102'});
serverAddress = result['value'] as String; serverAddress = result['value'] as String;
expect(serverAddress, 'http://127.0.0.1:9102'); expect(serverAddress, 'http://127.0.0.1:9102');
testedExtensions.add(FoundationServiceExtensions.activeDevToolsServerAddress.name);
}); });
test('Service extensions - connectedVmServiceUri', () async { test('Service extensions - connectedVmServiceUri', () async {
...@@ -979,5 +1038,7 @@ void main() { ...@@ -979,5 +1038,7 @@ void main() {
result = await binding.testExtension(FoundationServiceExtensions.connectedVmServiceUri.name, <String, String>{'value': 'http://127.0.0.1:54000/kMUMseKAnog=/'}); result = await binding.testExtension(FoundationServiceExtensions.connectedVmServiceUri.name, <String, String>{'value': 'http://127.0.0.1:54000/kMUMseKAnog=/'});
serverAddress = result['value'] as String; serverAddress = result['value'] as String;
expect(serverAddress, 'http://127.0.0.1:54000/kMUMseKAnog=/'); expect(serverAddress, 'http://127.0.0.1:54000/kMUMseKAnog=/');
testedExtensions.add(FoundationServiceExtensions.connectedVmServiceUri.name);
}); });
} }
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('reassemble with a className only marks subtrees from the first matching element as dirty', (WidgetTester tester) async {
await tester.pumpWidget(
const Foo(Bar(Fizz(SizedBox())))
);
expect(Foo.count, 0);
expect(Bar.count, 0);
expect(Fizz.count, 0);
DebugReassembleConfig config = DebugReassembleConfig(widgetName: 'Bar');
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
expect(Foo.count, 0);
expect(Bar.count, 1);
expect(Fizz.count, 1);
config = DebugReassembleConfig(widgetName: 'Fizz');
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
expect(Foo.count, 0);
expect(Bar.count, 1);
expect(Fizz.count, 2);
config = DebugReassembleConfig(widgetName: 'NoMatch');
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
expect(Foo.count, 0);
expect(Bar.count, 1);
expect(Fizz.count, 2);
config = DebugReassembleConfig();
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
expect(Foo.count, 1);
expect(Bar.count, 2);
expect(Fizz.count, 3);
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, null);
expect(Foo.count, 2);
expect(Bar.count, 3);
expect(Fizz.count, 4);
});
}
class Foo extends StatefulWidget {
const Foo(this.child, {super.key});
final Widget child;
static int count = 0;
@override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
@override
void reassemble() {
Foo.count += 1;
super.reassemble();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
class Bar extends StatefulWidget {
const Bar(this.child, {super.key});
final Widget child;
static int count = 0;
@override
State<Bar> createState() => _BarState();
}
class _BarState extends State<Bar> {
@override
void reassemble() {
Bar.count += 1;
super.reassemble();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
class Fizz extends StatefulWidget {
const Fizz(this.child, {super.key});
final Widget child;
static int count = 0;
@override
State<Fizz> createState() => _FizzState();
}
class _FizzState extends State<Fizz> {
@override
void reassemble() {
Fizz.count += 1;
super.reassemble();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
...@@ -115,7 +115,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ...@@ -115,7 +115,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
final WidgetsBinding binding = WidgetsBinding.instance; final WidgetsBinding binding = WidgetsBinding.instance;
if (binding.rootElement != null) { if (binding.rootElement != null) {
binding.buildOwner!.reassemble(binding.rootElement!, null); binding.buildOwner!.reassemble(binding.rootElement!);
} }
} }
......
...@@ -33,7 +33,7 @@ String getDefaultCachedKernelPath({ ...@@ -33,7 +33,7 @@ String getDefaultCachedKernelPath({
}) { }) {
final StringBuffer buffer = StringBuffer(); final StringBuffer buffer = StringBuffer();
final List<String> cacheFrontEndOptions = extraFrontEndOptions.toList() final List<String> cacheFrontEndOptions = extraFrontEndOptions.toList()
..removeWhere((String arg) => arg.startsWith('--enable-experiment=') || arg == '--flutter-widget-cache'); ..removeWhere((String arg) => arg.startsWith('--enable-experiment='));
buffer.writeAll(dartDefines); buffer.writeAll(dartDefines);
buffer.writeAll(cacheFrontEndOptions); buffer.writeAll(cacheFrontEndOptions);
String buildPrefix = ''; String buildPrefix = '';
......
...@@ -401,7 +401,6 @@ class UpdateFSReport { ...@@ -401,7 +401,6 @@ class UpdateFSReport {
bool success = false, bool success = false,
int invalidatedSourcesCount = 0, int invalidatedSourcesCount = 0,
int syncedBytes = 0, int syncedBytes = 0,
this.fastReassembleClassName,
int scannedSourcesCount = 0, int scannedSourcesCount = 0,
Duration compileDuration = Duration.zero, Duration compileDuration = Duration.zero,
Duration transferDuration = Duration.zero, Duration transferDuration = Duration.zero,
...@@ -423,7 +422,6 @@ class UpdateFSReport { ...@@ -423,7 +422,6 @@ class UpdateFSReport {
Duration get findInvalidatedDuration => _findInvalidatedDuration; Duration get findInvalidatedDuration => _findInvalidatedDuration;
bool _success; bool _success;
String? fastReassembleClassName;
int _invalidatedSourcesCount; int _invalidatedSourcesCount;
int _syncedBytes; int _syncedBytes;
int _scannedSourcesCount; int _scannedSourcesCount;
...@@ -435,7 +433,6 @@ class UpdateFSReport { ...@@ -435,7 +433,6 @@ class UpdateFSReport {
if (!report._success) { if (!report._success) {
_success = false; _success = false;
} }
fastReassembleClassName ??= report.fastReassembleClassName;
_invalidatedSourcesCount += report._invalidatedSourcesCount; _invalidatedSourcesCount += report._invalidatedSourcesCount;
_syncedBytes += report._syncedBytes; _syncedBytes += report._syncedBytes;
_scannedSourcesCount += report._scannedSourcesCount; _scannedSourcesCount += report._scannedSourcesCount;
...@@ -495,7 +492,6 @@ class DevFS { ...@@ -495,7 +492,6 @@ class DevFS {
DateTime? lastCompiled; DateTime? lastCompiled;
DateTime? _previousCompiled; DateTime? _previousCompiled;
PackageConfig? lastPackageConfig; PackageConfig? lastPackageConfig;
File? _widgetCacheOutputFile;
Uri? _baseUri; Uri? _baseUri;
Uri? get baseUri => _baseUri; Uri? get baseUri => _baseUri;
...@@ -555,22 +551,6 @@ class DevFS { ...@@ -555,22 +551,6 @@ class DevFS {
lastCompiled = _previousCompiled; lastCompiled = _previousCompiled;
} }
/// If the build method of a single widget was modified, return the widget name.
///
/// If any other changes were made, or there is an error scanning the file,
/// return `null`.
String? _checkIfSingleWidgetReloadApplied() {
final File? widgetCacheOutputFile = _widgetCacheOutputFile;
if (widgetCacheOutputFile != null && widgetCacheOutputFile.existsSync()) {
final String widget = widgetCacheOutputFile.readAsStringSync().trim();
if (widget.isNotEmpty) {
return widget;
}
}
return null;
}
/// Updates files on the device. /// Updates files on the device.
/// ///
/// Returns the number of bytes synced. /// Returns the number of bytes synced.
...@@ -596,7 +576,6 @@ class DevFS { ...@@ -596,7 +576,6 @@ class DevFS {
final DateTime candidateCompileTime = DateTime.now(); final DateTime candidateCompileTime = DateTime.now();
didUpdateFontManifest = false; didUpdateFontManifest = false;
lastPackageConfig = packageConfig; lastPackageConfig = packageConfig;
_widgetCacheOutputFile = _fileSystem.file('$dillOutputPath.incremental.dill.widget_cache');
// Update modified files // Update modified files
final Map<Uri, DevFSContent> dirtyEntries = <Uri, DevFSContent>{}; final Map<Uri, DevFSContent> dirtyEntries = <Uri, DevFSContent>{};
...@@ -741,7 +720,6 @@ class DevFS { ...@@ -741,7 +720,6 @@ class DevFS {
success: true, success: true,
syncedBytes: syncedBytes, syncedBytes: syncedBytes,
invalidatedSourcesCount: invalidatedFiles.length, invalidatedSourcesCount: invalidatedFiles.length,
fastReassembleClassName: _checkIfSingleWidgetReloadApplied(),
compileDuration: compileTimer.elapsed, compileDuration: compileTimer.elapsed,
transferDuration: transferTimer.elapsed, transferDuration: transferTimer.elapsed,
); );
......
...@@ -44,9 +44,6 @@ abstract class FeatureFlags { ...@@ -44,9 +44,6 @@ abstract class FeatureFlags {
/// Whether custom devices are enabled. /// Whether custom devices are enabled.
bool get areCustomDevicesEnabled => false; bool get areCustomDevicesEnabled => false;
/// Whether fast single widget reloads are enabled.
bool get isSingleWidgetReloadEnabled => false;
/// Whether WebAssembly compilation for Flutter Web is enabled. /// Whether WebAssembly compilation for Flutter Web is enabled.
bool get isFlutterWebWasmEnabled => false; bool get isFlutterWebWasmEnabled => false;
...@@ -62,7 +59,6 @@ const List<Feature> allFeatures = <Feature>[ ...@@ -62,7 +59,6 @@ const List<Feature> allFeatures = <Feature>[
flutterLinuxDesktopFeature, flutterLinuxDesktopFeature,
flutterMacOSDesktopFeature, flutterMacOSDesktopFeature,
flutterWindowsDesktopFeature, flutterWindowsDesktopFeature,
singleWidgetReload,
flutterAndroidFeature, flutterAndroidFeature,
flutterIOSFeature, flutterIOSFeature,
flutterFuchsiaFeature, flutterFuchsiaFeature,
...@@ -140,20 +136,6 @@ const Feature flutterCustomDevicesFeature = Feature( ...@@ -140,20 +136,6 @@ const Feature flutterCustomDevicesFeature = Feature(
), ),
); );
/// The fast hot reload feature for https://github.com/flutter/flutter/issues/61407.
const Feature singleWidgetReload = Feature(
name: 'Hot reload optimization for changes to class body of a single widget',
configSetting: 'single-widget-reload-optimization',
environmentOverride: 'FLUTTER_SINGLE_WIDGET_RELOAD',
master: FeatureChannelSetting(
available: true,
enabledByDefault: true,
),
beta: FeatureChannelSetting(
available: true,
),
);
/// Enabling WebAssembly compilation from `flutter build web` /// Enabling WebAssembly compilation from `flutter build web`
const Feature flutterWebWasm = Feature( const Feature flutterWebWasm = Feature(
name: 'WebAssembly compilation from flutter build web', name: 'WebAssembly compilation from flutter build web',
......
...@@ -44,9 +44,6 @@ class FlutterFeatureFlags implements FeatureFlags { ...@@ -44,9 +44,6 @@ class FlutterFeatureFlags implements FeatureFlags {
@override @override
bool get areCustomDevicesEnabled => isEnabled(flutterCustomDevicesFeature); bool get areCustomDevicesEnabled => isEnabled(flutterCustomDevicesFeature);
@override
bool get isSingleWidgetReloadEnabled => isEnabled(singleWidgetReload);
@override @override
bool get isFlutterWebWasmEnabled => isEnabled(flutterWebWasm); bool get isFlutterWebWasmEnabled => isEnabled(flutterWebWasm);
......
...@@ -446,7 +446,6 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). ...@@ -446,7 +446,6 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
fullRestart: true, fullRestart: true,
reason: reason, reason: reason,
overallTimeInMs: elapsed.inMilliseconds, overallTimeInMs: elapsed.inMilliseconds,
fastReassemble: false,
).send(); ).send();
} }
return OperationResult.ok; return OperationResult.ok;
......
...@@ -58,7 +58,6 @@ class CustomDimensions { ...@@ -58,7 +58,6 @@ class CustomDimensions {
this.commandRunAndroidEmbeddingVersion, this.commandRunAndroidEmbeddingVersion,
this.commandPackagesAndroidEmbeddingVersion, this.commandPackagesAndroidEmbeddingVersion,
this.nullSafety, this.nullSafety,
this.fastReassemble,
this.nullSafeMigratedLibraries, this.nullSafeMigratedLibraries,
this.nullSafeTotalLibraries, this.nullSafeTotalLibraries,
this.hotEventCompileTimeInMs, this.hotEventCompileTimeInMs,
...@@ -118,17 +117,17 @@ class CustomDimensions { ...@@ -118,17 +117,17 @@ class CustomDimensions {
final String? commandRunAndroidEmbeddingVersion; // cd45 final String? commandRunAndroidEmbeddingVersion; // cd45
final String? commandPackagesAndroidEmbeddingVersion; // cd46 final String? commandPackagesAndroidEmbeddingVersion; // cd46
final bool? nullSafety; // cd47 final bool? nullSafety; // cd47
final bool? fastReassemble; // cd48 // cd48 was fastReassemble but that feature was removed
final int? nullSafeMigratedLibraries; // cd49 final int? nullSafeMigratedLibraries; // cd49
final int? nullSafeTotalLibraries; // cd50 final int? nullSafeTotalLibraries; // cd50
final int? hotEventCompileTimeInMs; // cd 51 final int? hotEventCompileTimeInMs; // cd51
final int? hotEventFindInvalidatedTimeInMs; // cd 52 final int? hotEventFindInvalidatedTimeInMs; // cd52
final int? hotEventScannedSourcesCount; // cd 53 final int? hotEventScannedSourcesCount; // cd53
final int? hotEventReassembleTimeInMs; // cd 54 final int? hotEventReassembleTimeInMs; // cd54
final int? hotEventReloadVMTimeInMs; // cd 55 final int? hotEventReloadVMTimeInMs; // cd55
final bool? commandRunEnableImpeller; // cd 56 final bool? commandRunEnableImpeller; // cd56
final String? commandRunIOSInterfaceType; // cd 57 final String? commandRunIOSInterfaceType; // cd57
final bool? commandRunIsTest; // cd 58 final bool? commandRunIsTest; // cd58
/// Convert to a map that will be used to upload to the analytics backend. /// Convert to a map that will be used to upload to the analytics backend.
Map<String, String> toMap() => <String, String>{ Map<String, String> toMap() => <String, String>{
...@@ -179,7 +178,6 @@ class CustomDimensions { ...@@ -179,7 +178,6 @@ class CustomDimensions {
if (commandRunAndroidEmbeddingVersion != null) CustomDimensionsEnum.commandRunAndroidEmbeddingVersion.cdKey: commandRunAndroidEmbeddingVersion.toString(), if (commandRunAndroidEmbeddingVersion != null) CustomDimensionsEnum.commandRunAndroidEmbeddingVersion.cdKey: commandRunAndroidEmbeddingVersion.toString(),
if (commandPackagesAndroidEmbeddingVersion != null) CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion.cdKey: commandPackagesAndroidEmbeddingVersion.toString(), if (commandPackagesAndroidEmbeddingVersion != null) CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion.cdKey: commandPackagesAndroidEmbeddingVersion.toString(),
if (nullSafety != null) CustomDimensionsEnum.nullSafety.cdKey: nullSafety.toString(), if (nullSafety != null) CustomDimensionsEnum.nullSafety.cdKey: nullSafety.toString(),
if (fastReassemble != null) CustomDimensionsEnum.fastReassemble.cdKey: fastReassemble.toString(),
if (nullSafeMigratedLibraries != null) CustomDimensionsEnum.nullSafeMigratedLibraries.cdKey: nullSafeMigratedLibraries.toString(), if (nullSafeMigratedLibraries != null) CustomDimensionsEnum.nullSafeMigratedLibraries.cdKey: nullSafeMigratedLibraries.toString(),
if (nullSafeTotalLibraries != null) CustomDimensionsEnum.nullSafeTotalLibraries.cdKey: nullSafeTotalLibraries.toString(), if (nullSafeTotalLibraries != null) CustomDimensionsEnum.nullSafeTotalLibraries.cdKey: nullSafeTotalLibraries.toString(),
if (hotEventCompileTimeInMs != null) CustomDimensionsEnum.hotEventCompileTimeInMs.cdKey: hotEventCompileTimeInMs.toString(), if (hotEventCompileTimeInMs != null) CustomDimensionsEnum.hotEventCompileTimeInMs.cdKey: hotEventCompileTimeInMs.toString(),
...@@ -247,7 +245,6 @@ class CustomDimensions { ...@@ -247,7 +245,6 @@ class CustomDimensions {
commandRunAndroidEmbeddingVersion: other.commandRunAndroidEmbeddingVersion ?? commandRunAndroidEmbeddingVersion, commandRunAndroidEmbeddingVersion: other.commandRunAndroidEmbeddingVersion ?? commandRunAndroidEmbeddingVersion,
commandPackagesAndroidEmbeddingVersion: other.commandPackagesAndroidEmbeddingVersion ?? commandPackagesAndroidEmbeddingVersion, commandPackagesAndroidEmbeddingVersion: other.commandPackagesAndroidEmbeddingVersion ?? commandPackagesAndroidEmbeddingVersion,
nullSafety: other.nullSafety ?? nullSafety, nullSafety: other.nullSafety ?? nullSafety,
fastReassemble: other.fastReassemble ?? fastReassemble,
nullSafeMigratedLibraries: other.nullSafeMigratedLibraries ?? nullSafeMigratedLibraries, nullSafeMigratedLibraries: other.nullSafeMigratedLibraries ?? nullSafeMigratedLibraries,
nullSafeTotalLibraries: other.nullSafeTotalLibraries ?? nullSafeTotalLibraries, nullSafeTotalLibraries: other.nullSafeTotalLibraries ?? nullSafeTotalLibraries,
hotEventCompileTimeInMs: other.hotEventCompileTimeInMs ?? hotEventCompileTimeInMs, hotEventCompileTimeInMs: other.hotEventCompileTimeInMs ?? hotEventCompileTimeInMs,
...@@ -309,7 +306,6 @@ class CustomDimensions { ...@@ -309,7 +306,6 @@ class CustomDimensions {
commandRunAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandRunAndroidEmbeddingVersion), commandRunAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandRunAndroidEmbeddingVersion),
commandPackagesAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion), commandPackagesAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion),
nullSafety: _extractBool(map, CustomDimensionsEnum.nullSafety), nullSafety: _extractBool(map, CustomDimensionsEnum.nullSafety),
fastReassemble: _extractBool(map, CustomDimensionsEnum.fastReassemble),
nullSafeMigratedLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeMigratedLibraries), nullSafeMigratedLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeMigratedLibraries),
nullSafeTotalLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeTotalLibraries), nullSafeTotalLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeTotalLibraries),
hotEventCompileTimeInMs: _extractInt(map, CustomDimensionsEnum.hotEventCompileTimeInMs), hotEventCompileTimeInMs: _extractInt(map, CustomDimensionsEnum.hotEventCompileTimeInMs),
...@@ -397,7 +393,7 @@ enum CustomDimensionsEnum { ...@@ -397,7 +393,7 @@ enum CustomDimensionsEnum {
commandRunAndroidEmbeddingVersion, // cd45 commandRunAndroidEmbeddingVersion, // cd45
commandPackagesAndroidEmbeddingVersion, // cd46 commandPackagesAndroidEmbeddingVersion, // cd46
nullSafety, // cd47 nullSafety, // cd47
fastReassemble, // cd48 obsolete1, // cd48 (was fastReassemble)
nullSafeMigratedLibraries, // cd49 nullSafeMigratedLibraries, // cd49
nullSafeTotalLibraries, // cd50 nullSafeTotalLibraries, // cd50
hotEventCompileTimeInMs, // cd51 hotEventCompileTimeInMs, // cd51
......
...@@ -39,7 +39,6 @@ class HotEvent extends UsageEvent { ...@@ -39,7 +39,6 @@ class HotEvent extends UsageEvent {
required this.sdkName, required this.sdkName,
required this.emulator, required this.emulator,
required this.fullRestart, required this.fullRestart,
required this.fastReassemble,
this.reason, this.reason,
this.finalLibraryCount, this.finalLibraryCount,
this.syncedLibraryCount, this.syncedLibraryCount,
...@@ -63,7 +62,6 @@ class HotEvent extends UsageEvent { ...@@ -63,7 +62,6 @@ class HotEvent extends UsageEvent {
final String sdkName; final String sdkName;
final bool emulator; final bool emulator;
final bool fullRestart; final bool fullRestart;
final bool fastReassemble;
final int? finalLibraryCount; final int? finalLibraryCount;
final int? syncedLibraryCount; final int? syncedLibraryCount;
final int? syncedClassesCount; final int? syncedClassesCount;
...@@ -94,7 +92,6 @@ class HotEvent extends UsageEvent { ...@@ -94,7 +92,6 @@ class HotEvent extends UsageEvent {
hotEventInvalidatedSourcesCount: invalidatedSourcesCount, hotEventInvalidatedSourcesCount: invalidatedSourcesCount,
hotEventTransferTimeInMs: transferTimeInMs, hotEventTransferTimeInMs: transferTimeInMs,
hotEventOverallTimeInMs: overallTimeInMs, hotEventOverallTimeInMs: overallTimeInMs,
fastReassemble: fastReassemble,
hotEventCompileTimeInMs: compileTimeInMs, hotEventCompileTimeInMs: compileTimeInMs,
hotEventFindInvalidatedTimeInMs: findInvalidatedTimeInMs, hotEventFindInvalidatedTimeInMs: findInvalidatedTimeInMs,
hotEventScannedSourcesCount: scannedSourcesCount, hotEventScannedSourcesCount: scannedSourcesCount,
......
...@@ -34,7 +34,6 @@ import 'compile.dart'; ...@@ -34,7 +34,6 @@ import 'compile.dart';
import 'convert.dart'; import 'convert.dart';
import 'devfs.dart'; import 'devfs.dart';
import 'device.dart'; import 'device.dart';
import 'features.dart';
import 'globals.dart' as globals; import 'globals.dart' as globals;
import 'ios/application_package.dart'; import 'ios/application_package.dart';
import 'ios/devices.dart'; import 'ios/devices.dart';
...@@ -169,11 +168,8 @@ class FlutterDevice { ...@@ -169,11 +168,8 @@ class FlutterDevice {
platform: platform, platform: platform,
); );
} else { } else {
// The flutter-widget-cache feature only applies to run mode.
List<String> extraFrontEndOptions = buildInfo.extraFrontEndOptions; List<String> extraFrontEndOptions = buildInfo.extraFrontEndOptions;
extraFrontEndOptions = <String>[ extraFrontEndOptions = <String>[
if (featureFlags.isSingleWidgetReloadEnabled)
'--flutter-widget-cache',
'--enable-experiment=alternative-invalidation-strategy', '--enable-experiment=alternative-invalidation-strategy',
...extraFrontEndOptions, ...extraFrontEndOptions,
]; ];
......
...@@ -20,7 +20,6 @@ import 'convert.dart'; ...@@ -20,7 +20,6 @@ import 'convert.dart';
import 'dart/package_map.dart'; import 'dart/package_map.dart';
import 'devfs.dart'; import 'devfs.dart';
import 'device.dart'; import 'device.dart';
import 'features.dart';
import 'globals.dart' as globals; import 'globals.dart' as globals;
import 'project.dart'; import 'project.dart';
import 'reporting/reporting.dart'; import 'reporting/reporting.dart';
...@@ -415,7 +414,6 @@ class HotRunner extends ResidentRunner { ...@@ -415,7 +414,6 @@ class HotRunner extends ResidentRunner {
sdkName: _sdkName!, sdkName: _sdkName!,
emulator: _emulator!, emulator: _emulator!,
fullRestart: false, fullRestart: false,
fastReassemble: false,
overallTimeInMs: appStartedTimer.elapsed.inMilliseconds, overallTimeInMs: appStartedTimer.elapsed.inMilliseconds,
compileTimeInMs: totalCompileTime.inMilliseconds, compileTimeInMs: totalCompileTime.inMilliseconds,
transferTimeInMs: totalLaunchAppTime.inMilliseconds, transferTimeInMs: totalLaunchAppTime.inMilliseconds,
...@@ -802,7 +800,6 @@ class HotRunner extends ResidentRunner { ...@@ -802,7 +800,6 @@ class HotRunner extends ResidentRunner {
emulator: emulator!, emulator: emulator!,
fullRestart: true, fullRestart: true,
reason: reason, reason: reason,
fastReassemble: false,
overallTimeInMs: restartTimer.elapsed.inMilliseconds, overallTimeInMs: restartTimer.elapsed.inMilliseconds,
syncedBytes: result.updateFSReport?.syncedBytes, syncedBytes: result.updateFSReport?.syncedBytes,
invalidatedSourcesCount: result.updateFSReport?.invalidatedSourcesCount, invalidatedSourcesCount: result.updateFSReport?.invalidatedSourcesCount,
...@@ -828,7 +825,6 @@ class HotRunner extends ResidentRunner { ...@@ -828,7 +825,6 @@ class HotRunner extends ResidentRunner {
emulator: emulator!, emulator: emulator!,
fullRestart: true, fullRestart: true,
reason: reason, reason: reason,
fastReassemble: false,
).send(); ).send();
} }
status?.cancel(); status?.cancel();
...@@ -878,7 +874,6 @@ class HotRunner extends ResidentRunner { ...@@ -878,7 +874,6 @@ class HotRunner extends ResidentRunner {
emulator: emulator!, emulator: emulator!,
fullRestart: false, fullRestart: false,
reason: reason, reason: reason,
fastReassemble: false,
).send(); ).send();
} else { } else {
HotEvent('exception', HotEvent('exception',
...@@ -887,7 +882,6 @@ class HotRunner extends ResidentRunner { ...@@ -887,7 +882,6 @@ class HotRunner extends ResidentRunner {
emulator: emulator!, emulator: emulator!,
fullRestart: false, fullRestart: false,
reason: reason, reason: reason,
fastReassemble: false,
).send(); ).send();
} }
return OperationResult(errorCode, errorMessage, fatal: true); return OperationResult(errorCode, errorMessage, fatal: true);
...@@ -971,7 +965,6 @@ class HotRunner extends ResidentRunner { ...@@ -971,7 +965,6 @@ class HotRunner extends ResidentRunner {
viewCache, viewCache,
onSlow, onSlow,
reloadMessage, reloadMessage,
updatedDevFS.fastReassembleClassName,
); );
shouldReportReloadTime = reassembleResult.shouldReportReloadTime; shouldReportReloadTime = reassembleResult.shouldReportReloadTime;
if (reassembleResult.reassembleViews.isEmpty) { if (reassembleResult.reassembleViews.isEmpty) {
...@@ -1005,7 +998,6 @@ class HotRunner extends ResidentRunner { ...@@ -1005,7 +998,6 @@ class HotRunner extends ResidentRunner {
syncedBytes: updatedDevFS.syncedBytes, syncedBytes: updatedDevFS.syncedBytes,
invalidatedSourcesCount: updatedDevFS.invalidatedSourcesCount, invalidatedSourcesCount: updatedDevFS.invalidatedSourcesCount,
transferTimeInMs: updatedDevFS.transferDuration.inMilliseconds, transferTimeInMs: updatedDevFS.transferDuration.inMilliseconds,
fastReassemble: featureFlags.isSingleWidgetReloadEnabled && updatedDevFS.fastReassembleClassName != null,
compileTimeInMs: updatedDevFS.compileDuration.inMilliseconds, compileTimeInMs: updatedDevFS.compileDuration.inMilliseconds,
findInvalidatedTimeInMs: updatedDevFS.findInvalidatedDuration.inMilliseconds, findInvalidatedTimeInMs: updatedDevFS.findInvalidatedDuration.inMilliseconds,
scannedSourcesCount: updatedDevFS.scannedSourcesCount, scannedSourcesCount: updatedDevFS.scannedSourcesCount,
...@@ -1225,7 +1217,6 @@ Future<OperationResult> defaultReloadSourcesHelper( ...@@ -1225,7 +1217,6 @@ Future<OperationResult> defaultReloadSourcesHelper(
emulator: emulator!, emulator: emulator!,
fullRestart: false, fullRestart: false,
reason: reason, reason: reason,
fastReassemble: false,
usage: usage, usage: usage,
).send(); ).send();
// Reset devFS lastCompileTime to ensure the file will still be marked // Reset devFS lastCompileTime to ensure the file will still be marked
...@@ -1288,7 +1279,6 @@ typedef ReassembleHelper = Future<ReassembleResult> Function( ...@@ -1288,7 +1279,6 @@ typedef ReassembleHelper = Future<ReassembleResult> Function(
Map<FlutterDevice?, List<FlutterView>> viewCache, Map<FlutterDevice?, List<FlutterView>> viewCache,
void Function(String message)? onSlow, void Function(String message)? onSlow,
String reloadMessage, String reloadMessage,
String? fastReassembleClassName,
); );
Future<ReassembleResult> _defaultReassembleHelper( Future<ReassembleResult> _defaultReassembleHelper(
...@@ -1296,7 +1286,6 @@ Future<ReassembleResult> _defaultReassembleHelper( ...@@ -1296,7 +1286,6 @@ Future<ReassembleResult> _defaultReassembleHelper(
Map<FlutterDevice?, List<FlutterView>> viewCache, Map<FlutterDevice?, List<FlutterView>> viewCache,
void Function(String message)? onSlow, void Function(String message)? onSlow,
String reloadMessage, String reloadMessage,
String? fastReassembleClassName,
) async { ) async {
// Check if any isolates are paused and reassemble those that aren't. // Check if any isolates are paused and reassemble those that aren't.
final Map<FlutterView, FlutterVmService?> reassembleViews = <FlutterView, FlutterVmService?>{}; final Map<FlutterView, FlutterVmService?> reassembleViews = <FlutterView, FlutterVmService?>{};
...@@ -1325,17 +1314,9 @@ Future<ReassembleResult> _defaultReassembleHelper( ...@@ -1325,17 +1314,9 @@ Future<ReassembleResult> _defaultReassembleHelper(
reassembleViews[view] = device.vmService; reassembleViews[view] = device.vmService;
// If the tool identified a change in a single widget, do a fast instead // If the tool identified a change in a single widget, do a fast instead
// of a full reassemble. // of a full reassemble.
Future<void> reassembleWork; final Future<void> reassembleWork = device.vmService!.flutterReassemble(
if (fastReassembleClassName != null) {
reassembleWork = device.vmService!.flutterFastReassemble(
isolateId: view.uiIsolate!.id!, isolateId: view.uiIsolate!.id!,
className: fastReassembleClassName,
); );
} else {
reassembleWork = device.vmService!.flutterReassemble(
isolateId: view.uiIsolate!.id!,
);
}
reassembleFutures.add(reassembleWork.then( reassembleFutures.add(reassembleWork.then(
(Object? obj) => obj, (Object? obj) => obj,
onError: (Object error, StackTrace stackTrace) { onError: (Object error, StackTrace stackTrace) {
......
...@@ -809,19 +809,6 @@ class FlutterVmService { ...@@ -809,19 +809,6 @@ class FlutterVmService {
); );
} }
Future<Map<String, Object?>?> flutterFastReassemble({
required String isolateId,
required String className,
}) {
return invokeFlutterExtensionRpcRaw(
'ext.flutter.fastReassemble',
isolateId: isolateId,
args: <String, Object>{
'className': className,
},
);
}
Future<bool> flutterAlreadyPaintedFirstUsefulFrame({ Future<bool> flutterAlreadyPaintedFirstUsefulFrame({
required String isolateId, required String isolateId,
}) async { }) async {
......
...@@ -118,14 +118,14 @@ void main() { ...@@ -118,14 +118,14 @@ void main() {
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testWithoutContext('--flutter-widget-cache and --enable-experiment are removed from getDefaultCachedKernelPath hash', () { testWithoutContext('--enable-experiment is removed from getDefaultCachedKernelPath hash', () {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final Config config = Config.test(); final Config config = Config.test();
expect(getDefaultCachedKernelPath( expect(getDefaultCachedKernelPath(
trackWidgetCreation: true, trackWidgetCreation: true,
dartDefines: <String>[], dartDefines: <String>[],
extraFrontEndOptions: <String>['--enable-experiment=foo', '--flutter-widget-cache'], extraFrontEndOptions: <String>['--enable-experiment=foo'],
fileSystem: fileSystem, fileSystem: fileSystem,
config: config, config: config,
), 'build/cache.dill.track.dill'); ), 'build/cache.dill.track.dill');
...@@ -133,7 +133,7 @@ void main() { ...@@ -133,7 +133,7 @@ void main() {
expect(getDefaultCachedKernelPath( expect(getDefaultCachedKernelPath(
trackWidgetCreation: true, trackWidgetCreation: true,
dartDefines: <String>['foo=bar'], dartDefines: <String>['foo=bar'],
extraFrontEndOptions: <String>['--enable-experiment=foo', '--flutter-widget-cache'], extraFrontEndOptions: <String>['--enable-experiment=foo'],
fileSystem: fileSystem, fileSystem: fileSystem,
config: config, config: config,
), 'build/06ad47d8e64bd28de537b62ff85357c4.cache.dill.track.dill'); ), 'build/06ad47d8e64bd28de537b62ff85357c4.cache.dill.track.dill');
...@@ -141,7 +141,7 @@ void main() { ...@@ -141,7 +141,7 @@ void main() {
expect(getDefaultCachedKernelPath( expect(getDefaultCachedKernelPath(
trackWidgetCreation: false, trackWidgetCreation: false,
dartDefines: <String>[], dartDefines: <String>[],
extraFrontEndOptions: <String>['--enable-experiment=foo', '--flutter-widget-cache'], extraFrontEndOptions: <String>['--enable-experiment=foo'],
fileSystem: fileSystem, fileSystem: fileSystem,
config: config, config: config,
), 'build/cache.dill'); ), 'build/cache.dill');
...@@ -149,7 +149,7 @@ void main() { ...@@ -149,7 +149,7 @@ void main() {
expect(getDefaultCachedKernelPath( expect(getDefaultCachedKernelPath(
trackWidgetCreation: true, trackWidgetCreation: true,
dartDefines: <String>[], dartDefines: <String>[],
extraFrontEndOptions: <String>['--enable-experiment=foo', '--flutter-widget-cache', '--foo=bar'], extraFrontEndOptions: <String>['--enable-experiment=foo', '--foo=bar'],
fileSystem: fileSystem, fileSystem: fileSystem,
config: config, config: config,
), 'build/95b595cca01caa5f0ca0a690339dd7f6.cache.dill.track.dill'); ), 'build/95b595cca01caa5f0ca0a690339dd7f6.cache.dill.track.dill');
......
...@@ -178,7 +178,6 @@ void main() { ...@@ -178,7 +178,6 @@ void main() {
Map<FlutterDevice?, List<FlutterView>> viewCache, Map<FlutterDevice?, List<FlutterView>> viewCache,
void Function(String message)? onSlow, void Function(String message)? onSlow,
String reloadMessage, String reloadMessage,
String? fastReassembleClassName,
) async => ReassembleResult( ) async => ReassembleResult(
<FlutterView?, FlutterVmService?>{null: null}, <FlutterView?, FlutterVmService?>{null: null},
false, false,
...@@ -296,7 +295,6 @@ void main() { ...@@ -296,7 +295,6 @@ void main() {
hotEventSdkName: 'Tester', hotEventSdkName: 'Tester',
hotEventEmulator: false, hotEventEmulator: false,
hotEventFullRestart: true, hotEventFullRestart: true,
fastReassemble: false,
hotEventOverallTimeInMs: 64000, hotEventOverallTimeInMs: 64000,
hotEventSyncedBytes: 4, hotEventSyncedBytes: 4,
hotEventInvalidatedSourcesCount: 2, hotEventInvalidatedSourcesCount: 2,
...@@ -379,7 +377,6 @@ void main() { ...@@ -379,7 +377,6 @@ void main() {
Map<FlutterDevice?, List<FlutterView>> viewCache, Map<FlutterDevice?, List<FlutterView>> viewCache,
void Function(String message)? onSlow, void Function(String message)? onSlow,
String reloadMessage, String reloadMessage,
String? fastReassembleClassName,
) async => ReassembleResult( ) async => ReassembleResult(
<FlutterView?, FlutterVmService?>{null: null}, <FlutterView?, FlutterVmService?>{null: null},
false, false,
...@@ -402,7 +399,6 @@ void main() { ...@@ -402,7 +399,6 @@ void main() {
hotEventSdkName: 'Tester', hotEventSdkName: 'Tester',
hotEventEmulator: false, hotEventEmulator: false,
hotEventFullRestart: false, hotEventFullRestart: false,
fastReassemble: false,
hotEventCompileTimeInMs: 16000, hotEventCompileTimeInMs: 16000,
hotEventFindInvalidatedTimeInMs: 64000, hotEventFindInvalidatedTimeInMs: 64000,
hotEventScannedSourcesCount: 16, hotEventScannedSourcesCount: 16,
......
...@@ -25,7 +25,6 @@ import 'package:flutter_tools/src/convert.dart'; ...@@ -25,7 +25,6 @@ import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
...@@ -424,7 +423,6 @@ void main() { ...@@ -424,7 +423,6 @@ void main() {
hotEventSdkName: 'Android', hotEventSdkName: 'Android',
hotEventEmulator: false, hotEventEmulator: false,
hotEventFullRestart: false, hotEventFullRestart: false,
fastReassemble: false,
)), )),
)); ));
expect(fakeVmServiceHost?.hasRemainingExpectations, false); expect(fakeVmServiceHost?.hasRemainingExpectations, false);
...@@ -480,7 +478,6 @@ void main() { ...@@ -480,7 +478,6 @@ void main() {
hotEventSdkName: 'Android', hotEventSdkName: 'Android',
hotEventEmulator: false, hotEventEmulator: false,
hotEventFullRestart: false, hotEventFullRestart: false,
fastReassemble: false,
)), )),
)); ));
expect(fakeVmServiceHost?.hasRemainingExpectations, false); expect(fakeVmServiceHost?.hasRemainingExpectations, false);
...@@ -527,7 +524,6 @@ void main() { ...@@ -527,7 +524,6 @@ void main() {
hotEventSdkName: 'Android', hotEventSdkName: 'Android',
hotEventEmulator: false, hotEventEmulator: false,
hotEventFullRestart: false, hotEventFullRestart: false,
fastReassemble: false,
)), )),
)); ));
expect(fakeVmServiceHost?.hasRemainingExpectations, false); expect(fakeVmServiceHost?.hasRemainingExpectations, false);
...@@ -766,96 +762,6 @@ void main() { ...@@ -766,96 +762,6 @@ void main() {
Usage: () => TestUsage(), Usage: () => TestUsage(),
})); }));
testUsingContext('ResidentRunner can perform fast reassemble', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews,
FakeVmServiceRequest(
method: 'getVM',
jsonResponse: fakeVM.toJson(),
),
listViews,
listViews,
FakeVmServiceRequest(
method: 'getVM',
jsonResponse: fakeVM.toJson(),
),
const FakeVmServiceRequest(
method: kReloadSourcesServiceName,
args: <String, Object>{
'isolateId': '1',
'pause': false,
'rootLibUri': 'main.dart.incremental.dill',
},
jsonResponse: <String, Object>{
'type': 'ReloadReport',
'success': true,
'details': <String, Object>{
'loadedLibraryCount': 1,
},
},
),
FakeVmServiceRequest(
method: 'getIsolatePauseEvent',
args: <String, Object>{
'isolateId': '1',
},
jsonResponse: fakeUnpausedEvent.toJson(),
),
FakeVmServiceRequest(
method: 'ext.flutter.fastReassemble',
args: <String, Object?>{
'isolateId': fakeUnpausedIsolate.id,
'className': 'FOO',
},
),
]);
final FakeDelegateFlutterDevice flutterDevice = FakeDelegateFlutterDevice(
device,
BuildInfo.debug,
FakeResidentCompiler(),
devFS,
)..vmService = fakeVmServiceHost!.vmService;
residentRunner = HotRunner(
<FlutterDevice>[
flutterDevice,
],
stayResident: false,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
target: 'main.dart',
devtoolsHandler: createNoOpHandler,
);
devFS.nextUpdateReport = UpdateFSReport(
success: true,
fastReassembleClassName: 'FOO',
invalidatedSourcesCount: 1,
);
final Completer<DebugConnectionInfo> futureConnectionInfo = Completer<DebugConnectionInfo>.sync();
final Completer<void> futureAppStart = Completer<void>.sync();
unawaited(residentRunner.attach(
appStartedCompleter: futureAppStart,
connectionInfoCompleter: futureConnectionInfo,
enableDevTools: true,
));
await futureAppStart.future;
final OperationResult result = await residentRunner.restart();
expect(result.fatal, false);
expect(result.code, 0);
final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
expect(event.category, 'hot');
expect(event.parameter, 'reload');
expect(event.parameters?.fastReassemble, true);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
Platform: () => FakePlatform(),
ProjectFileInvalidator: () => FakeProjectFileInvalidator(),
Usage: () => TestUsage(),
FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true),
}));
testUsingContext('ResidentRunner reports hot reload time details', () => testbed.run(() async { testUsingContext('ResidentRunner reports hot reload time details', () => testbed.run(() async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[ fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
listViews, listViews,
...@@ -893,10 +799,9 @@ void main() { ...@@ -893,10 +799,9 @@ void main() {
jsonResponse: fakeUnpausedEvent.toJson(), jsonResponse: fakeUnpausedEvent.toJson(),
), ),
FakeVmServiceRequest( FakeVmServiceRequest(
method: 'ext.flutter.fastReassemble', method: 'ext.flutter.reassemble',
args: <String, Object?>{ args: <String, Object?>{
'isolateId': fakeUnpausedIsolate.id, 'isolateId': fakeUnpausedIsolate.id,
'className': 'FOO',
}, },
), ),
]); ]);
...@@ -917,7 +822,6 @@ void main() { ...@@ -917,7 +822,6 @@ void main() {
); );
devFS.nextUpdateReport = UpdateFSReport( devFS.nextUpdateReport = UpdateFSReport(
success: true, success: true,
fastReassembleClassName: 'FOO',
invalidatedSourcesCount: 1, invalidatedSourcesCount: 1,
); );
...@@ -942,7 +846,6 @@ void main() { ...@@ -942,7 +846,6 @@ void main() {
Platform: () => FakePlatform(), Platform: () => FakePlatform(),
ProjectFileInvalidator: () => FakeProjectFileInvalidator(), ProjectFileInvalidator: () => FakeProjectFileInvalidator(),
Usage: () => TestUsage(), Usage: () => TestUsage(),
FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true),
})); }));
testUsingContext('ResidentRunner can send target platform to analytics from full restart', () => testbed.run(() async { testUsingContext('ResidentRunner can send target platform to analytics from full restart', () => testbed.run(() async {
...@@ -1225,7 +1128,6 @@ void main() { ...@@ -1225,7 +1128,6 @@ void main() {
hotEventSdkName: 'Android', hotEventSdkName: 'Android',
hotEventEmulator: false, hotEventEmulator: false,
hotEventFullRestart: true, hotEventFullRestart: true,
fastReassemble: false,
)), )),
)); ));
expect(fakeVmServiceHost?.hasRemainingExpectations, false); expect(fakeVmServiceHost?.hasRemainingExpectations, false);
...@@ -1984,30 +1886,6 @@ flutter: ...@@ -1984,30 +1886,6 @@ flutter:
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('FlutterDevice passes flutter-widget-cache flag when feature is enabled', () async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
final FakeDevice device = FakeDevice();
final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create(
device,
buildInfo: const BuildInfo(
BuildMode.debug,
'',
treeShakeIcons: false,
extraFrontEndOptions: <String>[],
),
target: null, platform: FakePlatform(),
)).generator as DefaultResidentCompiler?;
expect(residentCompiler!.extraFrontEndOptions,
contains('--flutter-widget-cache'));
}, overrides: <Type, Generator>{
Artifacts: () => Artifacts.test(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true),
});
testUsingContext('FlutterDevice passes alternative-invalidation-strategy flag', () async { testUsingContext('FlutterDevice passes alternative-invalidation-strategy flag', () async {
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]); fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
final FakeDevice device = FakeDevice(); final FakeDevice device = FakeDevice();
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_tools/src/base/file_system.dart';
import '../src/common.dart';
import 'test_data/single_widget_reload_project.dart';
import 'test_driver.dart';
import 'test_utils.dart';
void main() {
late Directory tempDir;
final SingleWidgetReloadProject project = SingleWidgetReloadProject();
late FlutterRunTestDriver flutter;
setUp(() async {
tempDir = createResolvedTempDirectorySync('hot_reload_test.');
await project.setUpIn(tempDir);
flutter = FlutterRunTestDriver(tempDir);
});
tearDown(() async {
await flutter.stop();
tryToDelete(tempDir);
});
testWithoutContext('newly added code executes during hot reload with single widget reloads, but only invalidated widget', () async {
final StringBuffer stdout = StringBuffer();
final StreamSubscription<String> subscription = flutter.stdout.listen(stdout.writeln);
await flutter.run(singleWidgetReloads: true);
project.uncommentHotReloadPrint();
try {
await flutter.hotReload();
expect(stdout.toString(), allOf(
contains('(((TICK 1)))'),
contains('(((((RELOAD WORKED)))))'),
// Does not invalidate parent widget, so second tick is not output.
isNot(contains('(((TICK 2)))'),
)));
} finally {
await subscription.cancel();
}
});
testWithoutContext('changes outside of the class body triggers a full reload', () async {
final StringBuffer stdout = StringBuffer();
final StreamSubscription<String> subscription = flutter.stdout.listen(stdout.writeln);
await flutter.run(singleWidgetReloads: true);
project.modifyFunction();
try {
await flutter.hotReload();
expect(stdout.toString(), allOf(
contains('(((TICK 1)))'),
contains('(((TICK 2)))'),
));
} finally {
await subscription.cancel();
}
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../test_utils.dart';
import 'project.dart';
class SingleWidgetReloadProject extends Project {
@override
final String pubspec = '''
name: test
environment:
sdk: '>=3.0.0-0 <4.0.0'
dependencies:
flutter:
sdk: flutter
''';
@override
final String main = r'''
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final ByteData message = const StringCodec().encodeMessage('AppLifecycleState.resumed')!;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) { });
runApp(MyApp());
}
int count = 1;
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// PARENT WIDGET
print('((((TICK $count))))');
count += 1;
return MaterialApp(
title: 'Flutter Demo',
home: SecondWidget(),
);
}
}
class SecondWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Do not remove the next line, it's uncommented by a test to verify that
// hot reloading worked:
// printHotReloadWorked();
return Container();
}
}
void printHotReloadWorked() {
// The call to this function is uncommented by a test to verify that hot
// reloading worked.
print('(((((RELOAD WORKED)))))');
}
''';
Uri get parentWidgetUri => mainDart;
int get parentWidgetLine => lineContaining(main, '// PARENT WIDGET');
void uncommentHotReloadPrint() {
final String newMainContents = main.replaceAll(
'// printHotReloadWorked();',
'printHotReloadWorked();',
);
writeFile(
fileSystem.path.join(dir.path, 'lib', 'main.dart'),
newMainContents,
writeFutureModifiedDate: true,
);
}
void modifyFunction() {
final String newMainContents = main.replaceAll(
'(((((RELOAD WORKED)))))',
'(((((RELOAD WORKED 2)))))',
);
writeFile(
fileSystem.path.join(dir.path, 'lib', 'main.dart'),
newMainContents,
writeFutureModifiedDate: true,
);
}
}
...@@ -90,7 +90,6 @@ abstract class FlutterTestDriver { ...@@ -90,7 +90,6 @@ abstract class FlutterTestDriver {
List<String> arguments, { List<String> arguments, {
String? script, String? script,
bool withDebugger = false, bool withDebugger = false,
bool singleWidgetReloads = false,
}) async { }) async {
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
if (withDebugger) { if (withDebugger) {
...@@ -114,8 +113,6 @@ abstract class FlutterTestDriver { ...@@ -114,8 +113,6 @@ abstract class FlutterTestDriver {
environment: <String, String>{ environment: <String, String>{
'FLUTTER_TEST': 'true', 'FLUTTER_TEST': 'true',
'FLUTTER_WEB': 'true', 'FLUTTER_WEB': 'true',
if (singleWidgetReloads)
'FLUTTER_SINGLE_WIDGET_RELOAD': 'true',
}, },
); );
...@@ -511,7 +508,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { ...@@ -511,7 +508,6 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool chrome = false, bool chrome = false,
bool expressionEvaluation = true, bool expressionEvaluation = true,
bool structuredErrors = false, bool structuredErrors = false,
bool singleWidgetReloads = false,
bool serveObservatory = false, bool serveObservatory = false,
String? script, String? script,
List<String>? additionalCommandArgs, List<String>? additionalCommandArgs,
...@@ -542,7 +538,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { ...@@ -542,7 +538,6 @@ class FlutterRunTestDriver extends FlutterTestDriver {
startPaused: startPaused, startPaused: startPaused,
pauseOnExceptions: pauseOnExceptions, pauseOnExceptions: pauseOnExceptions,
script: script, script: script,
singleWidgetReloads: singleWidgetReloads,
); );
} }
...@@ -551,7 +546,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { ...@@ -551,7 +546,6 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool withDebugger = false, bool withDebugger = false,
bool startPaused = false, bool startPaused = false,
bool pauseOnExceptions = false, bool pauseOnExceptions = false,
bool singleWidgetReloads = false,
bool serveObservatory = false, bool serveObservatory = false,
List<String>? additionalCommandArgs, List<String>? additionalCommandArgs,
}) async { }) async {
...@@ -573,7 +567,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { ...@@ -573,7 +567,6 @@ class FlutterRunTestDriver extends FlutterTestDriver {
withDebugger: withDebugger, withDebugger: withDebugger,
startPaused: startPaused, startPaused: startPaused,
pauseOnExceptions: pauseOnExceptions, pauseOnExceptions: pauseOnExceptions,
singleWidgetReloads: singleWidgetReloads,
attachPort: port, attachPort: port,
); );
} }
...@@ -585,7 +578,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { ...@@ -585,7 +578,6 @@ class FlutterRunTestDriver extends FlutterTestDriver {
bool withDebugger = false, bool withDebugger = false,
bool startPaused = false, bool startPaused = false,
bool pauseOnExceptions = false, bool pauseOnExceptions = false,
bool singleWidgetReloads = false,
int? attachPort, int? attachPort,
}) async { }) async {
assert(!startPaused || withDebugger); assert(!startPaused || withDebugger);
...@@ -593,7 +585,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { ...@@ -593,7 +585,6 @@ class FlutterRunTestDriver extends FlutterTestDriver {
args, args,
script: script, script: script,
withDebugger: withDebugger, withDebugger: withDebugger,
singleWidgetReloads: singleWidgetReloads,
); );
final Completer<void> prematureExitGuard = Completer<void>(); final Completer<void> prematureExitGuard = Completer<void>();
...@@ -806,13 +797,11 @@ class FlutterTestTestDriver extends FlutterTestDriver { ...@@ -806,13 +797,11 @@ class FlutterTestTestDriver extends FlutterTestDriver {
bool withDebugger = false, bool withDebugger = false,
bool pauseOnExceptions = false, bool pauseOnExceptions = false,
Future<void> Function()? beforeStart, Future<void> Function()? beforeStart,
bool singleWidgetReloads = false,
}) async { }) async {
await super._setupProcess( await super._setupProcess(
args, args,
script: script, script: script,
withDebugger: withDebugger, withDebugger: withDebugger,
singleWidgetReloads: singleWidgetReloads,
); );
// Stash the PID so that we can terminate the VM more reliably than using // Stash the PID so that we can terminate the VM more reliably than using
......
...@@ -443,7 +443,6 @@ class TestFeatureFlags implements FeatureFlags { ...@@ -443,7 +443,6 @@ class TestFeatureFlags implements FeatureFlags {
this.isMacOSEnabled = false, this.isMacOSEnabled = false,
this.isWebEnabled = false, this.isWebEnabled = false,
this.isWindowsEnabled = false, this.isWindowsEnabled = false,
this.isSingleWidgetReloadEnabled = false,
this.isAndroidEnabled = true, this.isAndroidEnabled = true,
this.isIOSEnabled = true, this.isIOSEnabled = true,
this.isFuchsiaEnabled = false, this.isFuchsiaEnabled = false,
...@@ -463,9 +462,6 @@ class TestFeatureFlags implements FeatureFlags { ...@@ -463,9 +462,6 @@ class TestFeatureFlags implements FeatureFlags {
@override @override
final bool isWindowsEnabled; final bool isWindowsEnabled;
@override
final bool isSingleWidgetReloadEnabled;
@override @override
final bool isAndroidEnabled; final bool isAndroidEnabled;
...@@ -492,8 +488,6 @@ class TestFeatureFlags implements FeatureFlags { ...@@ -492,8 +488,6 @@ class TestFeatureFlags implements FeatureFlags {
return isMacOSEnabled; return isMacOSEnabled;
case flutterWindowsDesktopFeature: case flutterWindowsDesktopFeature:
return isWindowsEnabled; return isWindowsEnabled;
case singleWidgetReload:
return isSingleWidgetReloadEnabled;
case flutterAndroidFeature: case flutterAndroidFeature:
return isAndroidEnabled; return isAndroidEnabled;
case flutterIOSFeature: case flutterIOSFeature:
......
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