From 0128cc413ad08fa66683b96a3e51736f99af05cc Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 15:30:25 -0700 Subject: [PATCH 01/16] Enable `avoid-async-call-in-sync-function` --- analysis_options.yaml | 1 + .../lib/src/screens/debugger/codeview.dart | 6 ++++-- .../src/screens/debugger/debugger_controller.dart | 1 + .../lib/src/screens/dtd/dtd_tools_screen.dart | 2 +- .../controls/enhance_tracing/enhance_tracing.dart | 1 + .../object_inspector/vm_simple_list_display.dart | 12 +++++++----- .../lib/src/service/service_extension_widgets.dart | 2 +- .../lib/src/shared/charts/flame_chart.dart | 9 +++------ .../preferences/_cpu_profiler_preferences.dart | 2 +- .../src/shared/preferences/_logging_preferences.dart | 2 +- .../src/shared/preferences/_network_preferences.dart | 2 +- .../lib/src/shared/ui/common_widgets.dart | 2 +- .../ide_shared/not_connected_overlay.dart | 4 +++- .../property_editor/property_editor_controller.dart | 8 +++++--- .../screens/inspector/inspector_screen_test.dart | 6 +++--- .../vm_developer_common_widgets_test.dart | 5 ++++- .../scenes/standalone_ui/mock_editor_widget.dart | 5 +++-- 17 files changed, 41 insertions(+), 29 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index c98b130d539..2cfb09d8a12 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -179,6 +179,7 @@ dcm: # - avoid-banned-imports # TODO(polina-c): add configuration - avoid-importing-entrypoint-exports: only-in-src: true + - avoid-async-call-in-sync-function # This does catch findings that unawaited_futures misses. - avoid-cascade-after-if-null - avoid-collection-methods-with-unrelated-types - avoid-duplicate-exports diff --git a/packages/devtools_app/lib/src/screens/debugger/codeview.dart b/packages/devtools_app/lib/src/screens/debugger/codeview.dart index d5f1ebd54da..03973944560 100644 --- a/packages/devtools_app/lib/src/screens/debugger/codeview.dart +++ b/packages/devtools_app/lib/src/screens/debugger/codeview.dart @@ -1380,8 +1380,10 @@ final defaultScriptPopupMenuOptions = [ final copyPackagePathOption = ScriptPopupMenuOption( label: 'Copy package path', icon: Icons.content_copy, - onSelected: (_, controller) => Clipboard.setData( - ClipboardData(text: controller.scriptLocation.value?.scriptRef.uri ?? ''), + onSelected: (_, controller) => unawaited( + Clipboard.setData( + ClipboardData(text: controller.scriptLocation.value?.scriptRef.uri ?? ''), + ), ), ); diff --git a/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart b/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart index 485fed02bd8..01177d53466 100644 --- a/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart +++ b/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart @@ -402,6 +402,7 @@ class DebuggerController extends DevToolsScreenController /// cache, in order to reduce flashing in the editor view. void _populateScriptAndShowLocation(ScriptRef scriptRef) { safeUnawaited( + // ignore: avoid-async-call-in-sync-function, safeUnawaited handles this. scriptManager.getScript(scriptRef).then((script) async { await codeViewController.showScriptLocation(ScriptLocation(scriptRef)); }), diff --git a/packages/devtools_app/lib/src/screens/dtd/dtd_tools_screen.dart b/packages/devtools_app/lib/src/screens/dtd/dtd_tools_screen.dart index 46779d295af..7ecfff938f2 100644 --- a/packages/devtools_app/lib/src/screens/dtd/dtd_tools_screen.dart +++ b/packages/devtools_app/lib/src/screens/dtd/dtd_tools_screen.dart @@ -193,7 +193,7 @@ class _DtdNotConnectedViewState extends State { Expanded( child: DevToolsClearableTextField( controller: textEditingController, - onSubmitted: (_) => _connect(), + onSubmitted: (_) => unawaited(_connect()), ), ), const SizedBox(width: defaultSpacing), diff --git a/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart b/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart index 1e708a31f77..8dd85f2351e 100644 --- a/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart +++ b/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart @@ -144,6 +144,7 @@ class _TraceWidgetBuildsSettingState extends State safeUnawaited( serviceConnection.serviceManager.serviceExtensionManager + // ignore: avoid-async-call-in-sync-function, safeUnawaited handles this. .waitForServiceExtensionAvailable(extension.extension) .then((isServiceAvailable) { if (isServiceAvailable) { diff --git a/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart b/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart index bde64b1ab15..cedeaad9de0 100644 --- a/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart +++ b/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart @@ -66,11 +66,13 @@ class _VmSimpleListDisplayState extends State { .value! .id!; final service = serviceConnection.serviceManager.service!; - _initialized = service - .getObject(isolateId, elementsInstance.id!) - .then( - (e) => entries.addAll((e as Instance).elements!.cast()), - ); + // ignore: avoid-async-call-in-sync-function, intentional assignment of a future. + _initialized = service.getObject(isolateId, elementsInstance.id!); + unawaited( + _initialized.then( + (e) => entries.addAll((e as Instance).elements!.cast()), + ), + ); return; } final elementsList = widget.vmObject.elementsAsList; diff --git a/packages/devtools_app/lib/src/service/service_extension_widgets.dart b/packages/devtools_app/lib/src/service/service_extension_widgets.dart index 10fab338b7a..422ecf41b3d 100644 --- a/packages/devtools_app/lib/src/service/service_extension_widgets.dart +++ b/packages/devtools_app/lib/src/service/service_extension_widgets.dart @@ -252,7 +252,7 @@ class _HotReloadScaffoldAction extends ScaffoldAction { : super( icon: hotReloadIcon, tooltip: HotReloadButton._hotReloadTooltip, - onPressed: (_) => _callHotReload(), + onPressed: (_) => unawaited(_callHotReload()), ); } diff --git a/packages/devtools_app/lib/src/shared/charts/flame_chart.dart b/packages/devtools_app/lib/src/shared/charts/flame_chart.dart index 26aa5d80cc4..5f8fdb64958 100644 --- a/packages/devtools_app/lib/src/shared/charts/flame_chart.dart +++ b/packages/devtools_app/lib/src/shared/charts/flame_chart.dart @@ -443,13 +443,11 @@ abstract class FlameChartState< ); return KeyEventResult.handled; } else if (eventKey == PhysicalKeyboardKey.keyA) { - // `unawaited` does not work for FutureOr - // ignore: discarded_futures + // ignore: discarded_futures, avoid-async-call-in-sync-function, `unawaited` does not work for FutureOr scrollToX(horizontalControllerGroup.offset - keyboardScrollUnit); return KeyEventResult.handled; } else if (eventKey == PhysicalKeyboardKey.keyD) { - // `unawaited` does not work for FutureOr - // ignore: discarded_futures + // ignore: discarded_futures, avoid-async-call-in-sync-function, `unawaited` does not work for FutureOr scrollToX(horizontalControllerGroup.offset + keyboardScrollUnit); return KeyEventResult.handled; } @@ -480,8 +478,7 @@ abstract class FlameChartState< // to call this that guarantees the scroll controller offsets will be // updated for the new zoom level and layout size // https://github.com/flutter/devtools/issues/2012. - // `unawaited` does not work for FutureOr - // ignore: discarded_futures + // ignore: discarded_futures, avoid-async-call-in-sync-function, `unawaited` does not work for FutureOr scrollToX(newScrollOffset, jump: true); }); } diff --git a/packages/devtools_app/lib/src/shared/preferences/_cpu_profiler_preferences.dart b/packages/devtools_app/lib/src/shared/preferences/_cpu_profiler_preferences.dart index f93e042a122..d6117c9cbf2 100644 --- a/packages/devtools_app/lib/src/shared/preferences/_cpu_profiler_preferences.dart +++ b/packages/devtools_app/lib/src/shared/preferences/_cpu_profiler_preferences.dart @@ -19,7 +19,7 @@ class CpuProfilerPreferencesController extends DisposableController filterTag.value = await storage.getValue(filterStorageId) ?? ''; addAutoDisposeListener( filterTag, - () => storage.setValue(filterStorageId, filterTag.value), + () => unawaited(storage.setValue(filterStorageId, filterTag.value)), ); } } diff --git a/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart b/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart index 5257ce06fa9..633a880c89e 100644 --- a/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart +++ b/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart @@ -72,7 +72,7 @@ class LoggingPreferencesController extends DisposableController filterTag.value = await storage.getValue(filterStorageId) ?? ''; addAutoDisposeListener( filterTag, - () => storage.setValue(filterStorageId, filterTag.value), + () => unawaited(storage.setValue(filterStorageId, filterTag.value)), ); } } diff --git a/packages/devtools_app/lib/src/shared/preferences/_network_preferences.dart b/packages/devtools_app/lib/src/shared/preferences/_network_preferences.dart index 0a695be84fa..761b4fe743c 100644 --- a/packages/devtools_app/lib/src/shared/preferences/_network_preferences.dart +++ b/packages/devtools_app/lib/src/shared/preferences/_network_preferences.dart @@ -19,7 +19,7 @@ class NetworkPreferencesController extends DisposableController filterTag.value = await storage.getValue(filterStorageId) ?? ''; addAutoDisposeListener( filterTag, - () => storage.setValue(filterStorageId, filterTag.value), + () => unawaited(storage.setValue(filterStorageId, filterTag.value)), ); } } diff --git a/packages/devtools_app/lib/src/shared/ui/common_widgets.dart b/packages/devtools_app/lib/src/shared/ui/common_widgets.dart index d26a6cb4487..7d191ec2400 100644 --- a/packages/devtools_app/lib/src/shared/ui/common_widgets.dart +++ b/packages/devtools_app/lib/src/shared/ui/common_widgets.dart @@ -947,7 +947,7 @@ class _JsonViewerState extends State { ); // Creates tree structure } // Intended to be unawaited. - // ignore: discarded_futures + // ignore: discarded_futures, avoid-async-call-in-sync-function _initializeTree = _buildAndExpand(variable); } diff --git a/packages/devtools_app/lib/src/standalone_ui/ide_shared/not_connected_overlay.dart b/packages/devtools_app/lib/src/standalone_ui/ide_shared/not_connected_overlay.dart index 0a67722ffdd..7d2600f21ba 100644 --- a/packages/devtools_app/lib/src/standalone_ui/ide_shared/not_connected_overlay.dart +++ b/packages/devtools_app/lib/src/standalone_ui/ide_shared/not_connected_overlay.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. +import 'dart:async'; + import 'package:devtools_app_shared/service.dart'; import 'package:devtools_app_shared/ui.dart'; import 'package:flutter/material.dart'; @@ -51,7 +53,7 @@ class _NotConnectedOverlayState extends State { Text(stateLabel, style: theme.textTheme.headlineMedium), if (showReconnectButton) ElevatedButton( - onPressed: () => dtdManager.reconnect(), + onPressed: () => unawaited(dtdManager.reconnect()), child: const Text('Retry'), ), ], diff --git a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart index 977798d8481..bf1409fe3ba 100644 --- a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart +++ b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart @@ -109,9 +109,11 @@ class PropertyEditorController extends DisposableController return; } _requestDebouncer.run( - () => _updateWithEditableWidgetData( - textDocument: textDocument, - cursorPosition: cursorPosition, + () => unawaited( + _updateWithEditableWidgetData( + textDocument: textDocument, + cursorPosition: cursorPosition, + ), ), ); }), diff --git a/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart b/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart index 32cebaa6212..74be7d37cf3 100644 --- a/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart +++ b/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart @@ -85,7 +85,7 @@ void main() { await fakeExtensionManager.fakeFrame(); } - void mockNoExtensionsAvailable() { + Future mockNoExtensionsAvailable() async { fakeExtensionManager.extensionValueOnDevice = { extensions.toggleOnDeviceWidgetInspector.extension: true, extensions.toggleSelectWidgetMode.extension: false, @@ -93,7 +93,7 @@ void main() { }; // Don't actually send any events to the client indicating that service // extensions are avaiable. - fakeExtensionManager.fakeFrame(); + await fakeExtensionManager.fakeFrame(); } testWidgetsWithWindowSize('builds its tab', windowSize, ( @@ -206,7 +206,7 @@ void main() { 'Test toggling service extension buttons with no extensions available', windowSize, (WidgetTester tester) async { - mockNoExtensionsAvailable(); + await mockNoExtensionsAvailable(); expect( fakeExtensionManager.extensionValueOnDevice[extensions .debugPaint diff --git a/packages/devtools_app/test/screens/vm_developer/object_inspector/vm_developer_common_widgets_test.dart b/packages/devtools_app/test/screens/vm_developer/object_inspector/vm_developer_common_widgets_test.dart index f2fe081c20e..9266a267df2 100644 --- a/packages/devtools_app/test/screens/vm_developer/object_inspector/vm_developer_common_widgets_test.dart +++ b/packages/devtools_app/test/screens/vm_developer/object_inspector/vm_developer_common_widgets_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. +import 'dart:async'; + import 'package:devtools_app/devtools_app.dart'; import 'package:devtools_app/src/screens/vm_developer/object_inspector/inbound_references_tree.dart'; import 'package:devtools_app/src/screens/vm_developer/vm_developer_common_widgets.dart'; @@ -281,7 +283,8 @@ void main() { InboundReferencesTree( controller: testObjectInspectorViewController, object: mockClassObject, - onExpanded: (bool _) => mockClassObject.requestInboundsRefs(), + onExpanded: (bool _) => + unawaited(mockClassObject.requestInboundsRefs()), ), ), ); diff --git a/packages/devtools_app/test/test_infra/scenes/standalone_ui/mock_editor_widget.dart b/packages/devtools_app/test/test_infra/scenes/standalone_ui/mock_editor_widget.dart index d13c09055af..bb9146b8b98 100644 --- a/packages/devtools_app/test/test_infra/scenes/standalone_ui/mock_editor_widget.dart +++ b/packages/devtools_app/test/test_infra/scenes/standalone_ui/mock_editor_widget.dart @@ -277,8 +277,9 @@ class _MockEditorWidgetState extends State children: [ const Text('DTD Connection: '), ElevatedButton( - onPressed: () => - dtdManager.disconnectImpl(allowReconnect: true), + onPressed: () => unawaited( + dtdManager.disconnectImpl(allowReconnect: true), + ), child: const Text('Drop Connection'), ), ], From 860a2c15728fae8f7a6ff7001f5f9edcd4ca6577 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 15:30:40 -0700 Subject: [PATCH 02/16] Fix a few comments. --- .../shared/config_specific/post_message/_post_message_stub.dart | 2 +- .../devtools_app_shared/lib/src/ui/theme/_ide_theme_web.dart | 2 +- packages/devtools_app_shared/lib/src/utils/url/_url_web.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart b/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart index 75b018d7ef4..6b5389e97d3 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart @@ -7,6 +7,6 @@ import 'post_message.dart'; Stream get onPostMessage => throw UnsupportedError('unsupported platform'); -// ignore: unused-code, the web implementation is a useful helper for posting messages on the window's parent; this stub is necessary for config specific imports. +// ignore: unused-code, the web implementation is a useful helper for posting messages on the window's parent; this stub is necessary for conditional imports. void postMessage(Object? _, String _) => throw UnsupportedError('unsupported platform'); diff --git a/packages/devtools_app_shared/lib/src/ui/theme/_ide_theme_web.dart b/packages/devtools_app_shared/lib/src/ui/theme/_ide_theme_web.dart index 993e9b70ac1..c1064222b64 100644 --- a/packages/devtools_app_shared/lib/src/ui/theme/_ide_theme_web.dart +++ b/packages/devtools_app_shared/lib/src/ui/theme/_ide_theme_web.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. -// ignore_for_file: unused-code, this file is exported via config specific exports. +// ignore_for_file: unused-code, this file is exported via a conditional export. import 'package:web/web.dart'; diff --git a/packages/devtools_app_shared/lib/src/utils/url/_url_web.dart b/packages/devtools_app_shared/lib/src/utils/url/_url_web.dart index 5fa176657cc..df8c7395cfb 100644 --- a/packages/devtools_app_shared/lib/src/utils/url/_url_web.dart +++ b/packages/devtools_app_shared/lib/src/utils/url/_url_web.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. -// ignore_for_file: unused-code, this file is exported via config specific exports. +// ignore_for_file: unused-code, this file is exported via conditional exports. import 'package:web/web.dart'; From ce3858877d398df49b6bdb1f4945b832d0c034ba Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 15:33:28 -0700 Subject: [PATCH 03/16] Enable `avoid-collapsible-if` --- analysis_options.yaml | 1 + .../debugger/program_explorer_model.dart | 21 ++++++++--------- .../inspector/inspector_controller.dart | 13 ++++------- .../controller/chart_pane_controller.dart | 23 +++++++++---------- .../flutter_frames_controller.dart | 11 ++++----- .../lib/src/service/vm_flags.dart | 21 ++++++++--------- .../import_export/import_export.dart | 19 ++++++++------- .../shared/diagnostics/inspector_service.dart | 22 ++++++++---------- .../lib/src/shared/framework/screen.dart | 15 ++++++------ .../primitives/extent_delegate_list.dart | 2 -- .../lib/src/shared/table/table.dart | 9 ++++---- .../lib/src/shared/ui/search.dart | 10 ++++---- 12 files changed, 76 insertions(+), 91 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 2cfb09d8a12..23dcd446a25 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -181,6 +181,7 @@ dcm: only-in-src: true - avoid-async-call-in-sync-function # This does catch findings that unawaited_futures misses. - avoid-cascade-after-if-null + - avoid-collapsible-if - avoid-collection-methods-with-unrelated-types - avoid-duplicate-exports - avoid-dynamic diff --git a/packages/devtools_app/lib/src/screens/debugger/program_explorer_model.dart b/packages/devtools_app/lib/src/screens/debugger/program_explorer_model.dart index d39907f1a6c..03246f3ce10 100644 --- a/packages/devtools_app/lib/src/screens/debugger/program_explorer_model.dart +++ b/packages/devtools_app/lib/src/screens/debugger/program_explorer_model.dart @@ -190,17 +190,16 @@ class VMServiceObjectNode extends TreeNode { ?.isolateNow ?.rootLib ?.uri; - if (rootLibUri != null) { - if (rootLibUri.startsWith('package:') || - rootLibUri.startsWith('google3:')) { - final parts = rootLibUri.split('/')..removeLast(); - final path = parts.join('/'); - for (int i = 0; i < root.children.length; ++i) { - if (root.children[i].name.startsWith(path)) { - final rootLibNode = root.removeChildAtIndex(i); - root.addChild(rootLibNode, index: 0); - break; - } + if (rootLibUri != null && + (rootLibUri.startsWith('package:') || + rootLibUri.startsWith('google3:'))) { + final parts = rootLibUri.split('/')..removeLast(); + final path = parts.join('/'); + for (int i = 0; i < root.children.length; ++i) { + if (root.children[i].name.startsWith(path)) { + final rootLibNode = root.removeChildAtIndex(i); + root.addChild(rootLibNode, index: 0); + break; } } } diff --git a/packages/devtools_app/lib/src/screens/inspector/inspector_controller.dart b/packages/devtools_app/lib/src/screens/inspector/inspector_controller.dart index b9049b0fb24..c4897a625bc 100644 --- a/packages/devtools_app/lib/src/screens/inspector/inspector_controller.dart +++ b/packages/devtools_app/lib/src/screens/inspector/inspector_controller.dart @@ -551,10 +551,9 @@ class InspectorController extends DisposableController }) { if (currentDistance > inRange.end) return null; - if (inRange.contains(currentDistance)) { - if (of.description == matching.description) { - return of; - } + if (inRange.contains(currentDistance) && + of.description == matching.description) { + return of; } final children = of.childrenNow; @@ -968,10 +967,8 @@ class InspectorController extends DisposableController required RemoteDiagnosticsNode? selection, bool notifyFlutterInspector = false, }) { - if (selection != null) { - if (selection.isCreatedByLocalProject) { - _navigateTo(selection); - } + if (selection != null && selection.isCreatedByLocalProject) { + _navigateTo(selection); } if (notifyFlutterInspector && selection != null) { diff --git a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/chart_pane_controller.dart b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/chart_pane_controller.dart index 9c3d6562c98..4562e92427c 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/chart_pane_controller.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/chart_pane_controller.dart @@ -87,18 +87,17 @@ class MemoryChartPaneController extends DisposableController void _maybeUpdateChart() { if (!isChartVisible.value) return; - if (!offlineDataController.showingOfflineData.value) { - if (_chartConnection == null) { - _chartConnection ??= _chartConnection = ChartVmConnection( - data.timeline, - isAndroidChartVisible: isAndroidChartVisible, - ); - if (serviceConnection.serviceManager.connectedState.value.connected) { - _chartConnection!.init(); - resume(); - } else { - data.isDeviceAndroid ??= false; - } + if (!offlineDataController.showingOfflineData.value && + _chartConnection == null) { + _chartConnection ??= _chartConnection = ChartVmConnection( + data.timeline, + isAndroidChartVisible: isAndroidChartVisible, + ); + if (serviceConnection.serviceManager.connectedState.value.connected) { + _chartConnection!.init(); + resume(); + } else { + data.isDeviceAndroid ??= false; } } _maybeCalculateAndroidChartVisibility(); diff --git a/packages/devtools_app/lib/src/screens/performance/panes/flutter_frames/flutter_frames_controller.dart b/packages/devtools_app/lib/src/screens/performance/panes/flutter_frames/flutter_frames_controller.dart index 309b5c7b4a4..7c8ab57a9ce 100644 --- a/packages/devtools_app/lib/src/screens/performance/panes/flutter_frames/flutter_frames_controller.dart +++ b/packages/devtools_app/lib/src/screens/performance/panes/flutter_frames/flutter_frames_controller.dart @@ -136,12 +136,11 @@ class FlutterFramesController extends PerformanceFeatureController { } void _maybeBadgeTabForJankyFrame(FlutterFrame frame) { - if (_badgeTabForJankyFrames.value) { - if (frame.isJanky(_displayRefreshRate.value)) { - serviceConnection.errorBadgeManager.incrementBadgeCount( - PerformanceScreen.id, - ); - } + if (_badgeTabForJankyFrames.value && + frame.isJanky(_displayRefreshRate.value)) { + serviceConnection.errorBadgeManager.incrementBadgeCount( + PerformanceScreen.id, + ); } } diff --git a/packages/devtools_app/lib/src/service/vm_flags.dart b/packages/devtools_app/lib/src/service/vm_flags.dart index 71d9955aed0..017f9d9447d 100644 --- a/packages/devtools_app/lib/src/service/vm_flags.dart +++ b/packages/devtools_app/lib/src/service/vm_flags.dart @@ -43,17 +43,16 @@ class VmFlagManager with DisposerMixin { @visibleForTesting void handleVmEvent(Event event) async { - if (event.kind == EventKind.kVMFlagUpdate) { - if (_flagNotifiers.containsKey(event.flag)) { - final currentFlag = _flagNotifiers[event.flag]!.value; - _flagNotifiers[event.flag]!.value = Flag.parse({ - 'name': currentFlag.name, - 'comment': currentFlag.comment, - 'modified': true, - 'valueAsString': event.newValue, - })!; - _flags.value = await service.getFlagList(); - } + if (event.kind == EventKind.kVMFlagUpdate && + _flagNotifiers.containsKey(event.flag)) { + final currentFlag = _flagNotifiers[event.flag]!.value; + _flagNotifiers[event.flag]!.value = Flag.parse({ + 'name': currentFlag.name, + 'comment': currentFlag.comment, + 'modified': true, + 'valueAsString': event.newValue, + })!; + _flags.value = await service.getFlagList(); } } diff --git a/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart b/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart index eed968af961..4bf16bc9aeb 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart @@ -77,16 +77,15 @@ class ImportController { return; } - if (activeScreenId == ScreenMetaData.performance.id) { - if (devToolsOfflineData.json.containsKey('traceEvents')) { - notificationService.push( - 'It looks like you are trying to load data that was saved from an ' - 'old version of DevTools. This data uses a legacy format that is no ' - 'longer supported. To load this file in DevTools, you will need to ' - 'downgrade your Flutter version to < 3.22.', - ); - return; - } + if (activeScreenId == ScreenMetaData.performance.id && + devToolsOfflineData.json.containsKey('traceEvents')) { + notificationService.push( + 'It looks like you are trying to load data that was saved from an ' + 'old version of DevTools. This data uses a legacy format that is no ' + 'longer supported. To load this file in DevTools, you will need to ' + 'downgrade your Flutter version to < 3.22.', + ); + return; } final connectedApp = OfflineConnectedApp.parse( diff --git a/packages/devtools_app/lib/src/shared/diagnostics/inspector_service.dart b/packages/devtools_app/lib/src/shared/diagnostics/inspector_service.dart index e9837552292..07ef1375c75 100644 --- a/packages/devtools_app/lib/src/shared/diagnostics/inspector_service.dart +++ b/packages/devtools_app/lib/src/shared/diagnostics/inspector_service.dart @@ -311,18 +311,16 @@ class InspectorService extends InspectorServiceBase { // determine the source of the inspector selection change directly from the // inspector selection changed event. final currentTime = DateTime.now().millisecondsSinceEpoch; - if (ref != null) { - if (_expectedSelectionChanges.containsKey(ref)) { - final times = _expectedSelectionChanges.remove(ref)!; - while (times.isNotEmpty) { - final time = times.removeAt(0); - if (time + _maxTimeDelaySelectionNotification >= currentTime) { - // We triggered this selection change ourselves. This logic would - // work fine without the timestamps for the typical case but we use - // the timestamps to be safe in case there is a bug and selection - // change events were somehow lost. - return true; - } + if (ref != null && _expectedSelectionChanges.containsKey(ref)) { + final times = _expectedSelectionChanges.remove(ref)!; + while (times.isNotEmpty) { + final time = times.removeAt(0); + if (time + _maxTimeDelaySelectionNotification >= currentTime) { + // We triggered this selection change ourselves. This logic would + // work fine without the timestamps for the typical case but we use + // the timestamps to be safe in case there is a bug and selection + // change events were somehow lost. + return true; } } } diff --git a/packages/devtools_app/lib/src/shared/framework/screen.dart b/packages/devtools_app/lib/src/shared/framework/screen.dart index 6e090ff7bc0..eb0f88852cc 100644 --- a/packages/devtools_app/lib/src/shared/framework/screen.dart +++ b/packages/devtools_app/lib/src/shared/framework/screen.dart @@ -502,14 +502,13 @@ abstract class Screen { ); } - if (screen.requiresAdvancedDeveloperMode) { - if (!preferences.advancedDeveloperModeEnabled.value) { - _log.finest('screen requires advanced developer mode: returning false'); - return ( - show: false, - disabledReason: ScreenDisabledReason.requiresAdvancedDeveloperMode, - ); - } + if (screen.requiresAdvancedDeveloperMode && + !preferences.advancedDeveloperModeEnabled.value) { + _log.finest('screen requires advanced developer mode: returning false'); + return ( + show: false, + disabledReason: ScreenDisabledReason.requiresAdvancedDeveloperMode, + ); } final serviceManager = serviceConnection.serviceManager; diff --git a/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart b/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart index 2beaaf3a100..e03599ace28 100644 --- a/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart +++ b/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart @@ -344,9 +344,7 @@ class RenderSliverExtentDelegateBoxAdaptor extends RenderSliverMultiBoxAdaptor { collectGarbage(leadingGarbage, trailingGarbage); } else { collectGarbage(0, 0); - } - if (firstChild == null) { if (!addInitialChild( index: firstIndex, layoutOffset: _extentDelegate!.layoutOffset(firstIndex), diff --git a/packages/devtools_app/lib/src/shared/table/table.dart b/packages/devtools_app/lib/src/shared/table/table.dart index 19da2a152a2..a96fdb22319 100644 --- a/packages/devtools_app/lib/src/shared/table/table.dart +++ b/packages/devtools_app/lib/src/shared/table/table.dart @@ -397,11 +397,10 @@ class DevToolsTableState extends State> final verticalScrollController = this.verticalScrollController; // If we're at the end already, scroll to expose the new content. - if (widget.autoScrollContent) { - if (verticalScrollController.hasClients && - verticalScrollController.atScrollBottom) { - unawaited(verticalScrollController.autoScrollToBottom()); - } + if (widget.autoScrollContent && + verticalScrollController.hasClients && + verticalScrollController.atScrollBottom) { + unawaited(verticalScrollController.autoScrollToBottom()); } final columnGroups = widget.tableController.columnGroups; diff --git a/packages/devtools_app/lib/src/shared/ui/search.dart b/packages/devtools_app/lib/src/shared/ui/search.dart index 573d0e016cc..d74974854fa 100644 --- a/packages/devtools_app/lib/src/shared/ui/search.dart +++ b/packages/devtools_app/lib/src/shared/ui/search.dart @@ -1250,15 +1250,13 @@ class _AutoCompleteSearchFieldState extends State } // Nothing found, pick item selected in dropdown. final autoCompleteList = widget.controller.searchAutoComplete.value; - if (foundExact == null || + if (autoCompleteList.isNotEmpty && foundExact == null || autoCompleteList[widget.controller.currentHoveredIndex.value] .text != foundExact) { - if (autoCompleteList.isNotEmpty) { - foundExact = - autoCompleteList[widget.controller.currentHoveredIndex.value] - .text; - } + foundExact = + autoCompleteList[widget.controller.currentHoveredIndex.value] + .text; } if (foundExact != null) { From 9f856cd081940ca67f8b9a9aaf0a6cf5bf87e8ad Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 15:33:51 -0700 Subject: [PATCH 04/16] Enable `avoid-accessing-collections-by-constant-index` --- analysis_options.yaml | 1 + .../test/screens/memory/shared/heap/heap_analyzer_test.dart | 1 + .../test/test_infra/test_data/memory/heap/heap_graph_fakes.dart | 1 + 3 files changed, 3 insertions(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index 23dcd446a25..fa178e67813 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -179,6 +179,7 @@ dcm: # - avoid-banned-imports # TODO(polina-c): add configuration - avoid-importing-entrypoint-exports: only-in-src: true + - avoid-accessing-collections-by-constant-index - avoid-async-call-in-sync-function # This does catch findings that unawaited_futures misses. - avoid-cascade-after-if-null - avoid-collapsible-if diff --git a/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart b/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart index 45e96c3aa81..05541973783 100644 --- a/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart +++ b/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart @@ -15,6 +15,7 @@ void main() { final heap = HeapData(t.heap, created: DateTime.now()); await heap.calculate; + // ignore: avoid-accessing-collections-by-constant-index, intentional use of special index. expect(heap.retainedSizes![heapRootIndex], equals(t.rootRetainedSize)); var actualUnreachableSize = 0; diff --git a/packages/devtools_app/test/test_infra/test_data/memory/heap/heap_graph_fakes.dart b/packages/devtools_app/test/test_infra/test_data/memory/heap/heap_graph_fakes.dart index eb11d7a4e5c..95e069d2ac9 100644 --- a/packages/devtools_app/test/test_infra/test_data/memory/heap/heap_graph_fakes.dart +++ b/packages/devtools_app/test/test_infra/test_data/memory/heap/heap_graph_fakes.dart @@ -93,6 +93,7 @@ class FakeHeapSnapshotGraph extends Fake implements HeapSnapshotGraph { ), ); final index = objects.length - 1; + // ignore: avoid-accessing-collections-by-constant-index, intentional use of special index. objects[heapRootIndex].addReference(index); } } From c2ec59e856fcd1b52a429c0d6141bb7ecfabf946 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 15:34:38 -0700 Subject: [PATCH 05/16] Add `avoid-banned-imports` --- analysis_options.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index fa178e67813..54ba527f26b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -175,15 +175,19 @@ dcm: # Ignore unused code in package examples. - packages/devtools_app_shared/example/** rules: -# - arguments-ordering Too strict -# - avoid-banned-imports # TODO(polina-c): add configuration - - avoid-importing-entrypoint-exports: - only-in-src: true - avoid-accessing-collections-by-constant-index - avoid-async-call-in-sync-function # This does catch findings that unawaited_futures misses. + - avoid-banned-imports: + entries: + - paths: ['packages/devtools_shared/lib/.*\.dart'] + deny: ['package:flutter/.*'] + message: 'Do not import Flutter libraries in devtools_shared.' + severity: error - avoid-cascade-after-if-null - avoid-collapsible-if - avoid-collection-methods-with-unrelated-types + - avoid-importing-entrypoint-exports: + only-in-src: true - avoid-duplicate-exports - avoid-dynamic # - avoid-global-state TODO(jacobr): bunch of false positives around boolean flags. From 8f2fc1b28edf56ab58719926cabda49f7132593d Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 15:44:03 -0700 Subject: [PATCH 06/16] Enable `avoid-constant-assert-conditions` --- analysis_options.yaml | 1 + .../src/screens/memory/panes/diff/data/classes_diff.dart | 8 +++++++- .../lib/src/shared/charts/chart_controller.dart | 5 ++++- .../devtools_app/lib/src/shared/console/console.dart | 9 +++++---- .../devtools_app/lib/src/shared/memory/class_name.dart | 5 ++++- .../test/screens/memory/chart/chart_test.dart | 4 ++-- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 54ba527f26b..3cbe08f7b65 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -186,6 +186,7 @@ dcm: - avoid-cascade-after-if-null - avoid-collapsible-if - avoid-collection-methods-with-unrelated-types + - avoid-constant-assert-conditions - avoid-importing-entrypoint-exports: only-in-src: true - avoid-duplicate-exports diff --git a/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart b/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart index 931023fdbc2..031f5387758 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. +import 'package:flutter/foundation.dart'; + import '../../../../../shared/memory/class_name.dart'; import '../../../../../shared/memory/classes.dart'; import '../../../../../shared/memory/heap_data.dart'; @@ -42,7 +44,11 @@ class ObjectSetDiff { continue; } - assert(false); + if (kDebugMode) { + throw Exception( + 'Unexpected state for code $code: before=$before, after=$after', + ); + } } assert( diff --git a/packages/devtools_app/lib/src/shared/charts/chart_controller.dart b/packages/devtools_app/lib/src/shared/charts/chart_controller.dart index 923ac1b2630..eff1df920f7 100644 --- a/packages/devtools_app/lib/src/shared/charts/chart_controller.dart +++ b/packages/devtools_app/lib/src/shared/charts/chart_controller.dart @@ -4,6 +4,7 @@ import 'package:collection/collection.dart'; import 'package:devtools_app_shared/utils.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../primitives/utils.dart'; @@ -315,7 +316,9 @@ class ChartController extends DisposableController labelInterval = labelsTwoMinutes; break; default: - assert(false, 'Unexpected Duration $rangeInMinutes'); + if (kDebugMode) { + throw Exception('Unexpected Duration $rangeInMinutes'); + } } } diff --git a/packages/devtools_app/lib/src/shared/console/console.dart b/packages/devtools_app/lib/src/shared/console/console.dart index 30e9913ae67..bd365eee02f 100644 --- a/packages/devtools_app/lib/src/shared/console/console.dart +++ b/packages/devtools_app/lib/src/shared/console/console.dart @@ -205,10 +205,11 @@ class _ConsoleOutputState extends State<_ConsoleOutput> isSelectable: false, ); } else { - assert( - false, - 'ConsoleLine of unsupported type ${line.runtimeType} encountered', - ); + if (kDebugMode) { + throw Exception( + 'ConsoleLine of unsupported type ${line.runtimeType} encountered', + ); + } return const SizedBox(); } }, diff --git a/packages/devtools_app/lib/src/shared/memory/class_name.dart b/packages/devtools_app/lib/src/shared/memory/class_name.dart index c966b4c8a7c..271ad6efb9a 100644 --- a/packages/devtools_app/lib/src/shared/memory/class_name.dart +++ b/packages/devtools_app/lib/src/shared/memory/class_name.dart @@ -3,6 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. import 'package:devtools_shared/devtools_shared.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:vm_service/vm_service.dart'; @@ -165,7 +166,9 @@ class HeapClassName with Serializable { // TODO(polina-c): create a way for users to add their weak classes // or detect weak references automatically, without hard coding // class names. - assert(false, 'Unexpected library for $className: $library.'); + if (kDebugMode) { + throw Exception('Unexpected library for $className: $library.'); + } return false; } diff --git a/packages/devtools_app/test/screens/memory/chart/chart_test.dart b/packages/devtools_app/test/screens/memory/chart/chart_test.dart index 620180e67fd..5b052d59250 100644 --- a/packages/devtools_app/test/screens/memory/chart/chart_test.dart +++ b/packages/devtools_app/test/screens/memory/chart/chart_test.dart @@ -564,10 +564,10 @@ void main() { } else if (monitorType.isReset) { addDataToTrace(controller, monitorResetTraceIndex, rawData); } else { - assert(false, 'Unknown monitor type'); + throw Exception('Unknown monitor type'); } } else if (event.isEmpty) { - assert(false, 'Unexpected EventSample of isEmpty.'); + throw Exception('Unexpected EventSample of isEmpty.'); } } } From 9c2cb4a8cc11697514b1249a9adb38f4ddfa3d06 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 16:07:19 -0700 Subject: [PATCH 07/16] Enable `avoid-duplicate-named-imports` --- analysis_options.yaml | 1 + .../charts/event_chart_controller.dart | 34 +++++++++---------- .../charts/vm_chart_controller.dart | 14 ++++---- .../controller/diff_pane_controller_test.dart | 11 ++---- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 3cbe08f7b65..869ffa72911 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -187,6 +187,7 @@ dcm: - avoid-collapsible-if - avoid-collection-methods-with-unrelated-types - avoid-constant-assert-conditions + - avoid-duplicate-named-imports - avoid-importing-entrypoint-exports: only-in-src: true - avoid-duplicate-exports diff --git a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/event_chart_controller.dart b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/event_chart_controller.dart index 29bbf2e95eb..9adcb391382 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/event_chart_controller.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/event_chart_controller.dart @@ -8,8 +8,6 @@ import 'package:flutter/material.dart'; import '../../../../../../shared/charts/chart_controller.dart'; import '../../../../../../shared/charts/chart_trace.dart' as chart_trace; -import '../../../../../../shared/charts/chart_trace.dart' - show ChartType, PaintCharacteristics, ChartSymbol; import '../../../../shared/primitives/memory_timeline.dart'; class _Sizes { @@ -132,11 +130,11 @@ class EventChartController extends ChartController { } final extensionEventsIndex = createTrace( - ChartType.symbol, - PaintCharacteristics( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics( color: Colors.purpleAccent[100]!, colorAggregate: Colors.purpleAccent[400], - symbol: ChartSymbol.filledTriangle, + symbol: chart_trace.ChartSymbol.filledTriangle, height: 20, width: 20, fixedMinY: _Sizes.visibleVm, @@ -151,8 +149,8 @@ class EventChartController extends ChartController { ); final snapshotIndex = createTrace( - ChartType.symbol, - PaintCharacteristics( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics( color: Colors.green, strokeWidth: 3, diameter: 6, @@ -169,8 +167,8 @@ class EventChartController extends ChartController { // Auto-snapshot final autoSnapshotIndex = createTrace( - ChartType.symbol, - PaintCharacteristics( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics( color: Colors.red, strokeWidth: 3, diameter: 6, @@ -187,8 +185,8 @@ class EventChartController extends ChartController { // Manual GC final manualGCIndex = createTrace( - ChartType.symbol, - PaintCharacteristics( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics( color: Colors.blue, strokeWidth: 3, diameter: 6, @@ -207,8 +205,8 @@ class EventChartController extends ChartController { // Monitor final monitorIndex = createTrace( - ChartType.symbol, - PaintCharacteristics( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics( color: mainMonitorColor, strokeWidth: 3, diameter: 6, @@ -224,8 +222,8 @@ class EventChartController extends ChartController { ); final monitorResetIndex = createTrace( - ChartType.symbol, - PaintCharacteristics.concentric( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics.concentric( color: Colors.grey[600]!, strokeWidth: 4, diameter: 6, @@ -244,10 +242,10 @@ class EventChartController extends ChartController { // VM GC final gcIndex = createTrace( - ChartType.symbol, - PaintCharacteristics( + chart_trace.ChartType.symbol, + chart_trace.PaintCharacteristics( color: Colors.blue, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 4, fixedMinY: _Sizes.visibleVm, fixedMaxY: _Sizes.extensions, diff --git a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/vm_chart_controller.dart b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/vm_chart_controller.dart index a84a8dc67aa..b5ef66a40cf 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/vm_chart_controller.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/vm_chart_controller.dart @@ -8,8 +8,6 @@ import 'package:flutter/material.dart'; import '../../../../../../shared/charts/chart_controller.dart'; import '../../../../../../shared/charts/chart_trace.dart' as chart_trace; -import '../../../../../../shared/charts/chart_trace.dart' - show ChartType, ChartSymbol; import '../../../../shared/primitives/memory_timeline.dart'; import '../../data/charts.dart'; @@ -133,7 +131,7 @@ class VMChartController extends ChartController { } final externalIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Colors.externals, symbol: chart_trace.ChartSymbol.disc, @@ -149,7 +147,7 @@ class VMChartController extends ChartController { // Used Heap final usedIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Colors.used, symbol: chart_trace.ChartSymbol.disc, @@ -163,11 +161,11 @@ class VMChartController extends ChartController { // Heap Capacity final capacityIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Colors.capacity, diameter: 0.0, - symbol: ChartSymbol.dashedLine, + symbol: chart_trace.ChartSymbol.dashedLine, ), name: VmTraceName.capacity.toString(), ); @@ -178,10 +176,10 @@ class VMChartController extends ChartController { // RSS final rSSIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Colors.rss, - symbol: ChartSymbol.dashedLine, + symbol: chart_trace.ChartSymbol.dashedLine, strokeWidth: 2, ), name: VmTraceName.rSS.toString(), diff --git a/packages/devtools_app/test/screens/memory/diff/controller/diff_pane_controller_test.dart b/packages/devtools_app/test/screens/memory/diff/controller/diff_pane_controller_test.dart index 8531dde587a..28cd1ce32e5 100644 --- a/packages/devtools_app/test/screens/memory/diff/controller/diff_pane_controller_test.dart +++ b/packages/devtools_app/test/screens/memory/diff/controller/diff_pane_controller_test.dart @@ -4,10 +4,8 @@ import 'package:devtools_app/src/screens/memory/framework/memory_tabs.dart'; import 'package:devtools_app/src/screens/memory/panes/diff/controller/diff_pane_controller.dart'; -import 'package:devtools_app/src/screens/memory/panes/diff/controller/diff_pane_controller.dart' - as diff_pane_controller - show Json; -import 'package:devtools_app/src/screens/memory/panes/diff/controller/snapshot_item.dart'; +import 'package:devtools_app/src/screens/memory/panes/diff/controller/snapshot_item.dart' + hide Json; import 'package:devtools_test/helpers.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -53,10 +51,7 @@ void main() { snapshots.first.diffWith.value = snapshots.last; final json = controller.toJson(); - expect( - json.keys.toSet(), - equals(diff_pane_controller.Json.values.map((e) => e.name).toSet()), - ); + expect(json.keys.toSet(), equals(Json.values.map((e) => e.name).toSet())); final fromJson = DiffPaneController.fromJson(json); final snapshotsFromJson = fromJson.core.snapshots.value From b8edd0f035f1eec7b6ecf29b86c2689ea528f227 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 16:10:03 -0700 Subject: [PATCH 08/16] address another file --- .../charts/android_chart_controller.dart | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/android_chart_controller.dart b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/android_chart_controller.dart index 247615b6eae..8e533089375 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/android_chart_controller.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/chart/controller/charts/android_chart_controller.dart @@ -8,8 +8,6 @@ import 'package:flutter/material.dart'; import '../../../../../../shared/charts/chart_controller.dart'; import '../../../../../../shared/charts/chart_trace.dart' as chart_trace; -import '../../../../../../shared/charts/chart_trace.dart' - show ChartType, ChartSymbol; import '../../../../shared/primitives/memory_timeline.dart'; import '../../data/charts.dart'; @@ -122,10 +120,10 @@ class AndroidChartController extends ChartController { // Stack trace final stackIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.stackColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -138,10 +136,10 @@ class AndroidChartController extends ChartController { // Java heap trace. final javaHeapIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.javaColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -155,10 +153,10 @@ class AndroidChartController extends ChartController { // Code trace final codeIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.codeColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -171,10 +169,10 @@ class AndroidChartController extends ChartController { // Graphics Trace final graphicIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.graphicColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -188,10 +186,10 @@ class AndroidChartController extends ChartController { // Native heap trace. final nativeHeapIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.nativeHeapColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -205,10 +203,10 @@ class AndroidChartController extends ChartController { // Other trace final otherIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.otherColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -221,10 +219,10 @@ class AndroidChartController extends ChartController { // System trace final systemIndex = createTrace( - ChartType.line, + chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.systemColor, - symbol: ChartSymbol.disc, + symbol: chart_trace.ChartSymbol.disc, diameter: 1.5, ), stacked: true, @@ -241,7 +239,7 @@ class AndroidChartController extends ChartController { chart_trace.ChartType.line, chart_trace.PaintCharacteristics( color: _Color.totalColor, - symbol: ChartSymbol.dashedLine, + symbol: chart_trace.ChartSymbol.dashedLine, strokeWidth: 2, ), name: AndroidTraceName.total.toString(), From 196258864a5e30eb6c6758fd5ac71b3a1fbebd5d Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 16:23:56 -0700 Subject: [PATCH 09/16] Add `avoid-empty-test-groups` --- analysis_options.yaml | 1 + .../test/screens/debugger/syntax_highlighter_test.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index 869ffa72911..6a08c7f3a77 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -188,6 +188,7 @@ dcm: - avoid-collection-methods-with-unrelated-types - avoid-constant-assert-conditions - avoid-duplicate-named-imports + - avoid-empty-test-groups - avoid-importing-entrypoint-exports: only-in-src: true - avoid-duplicate-exports diff --git a/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart b/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart index b8b8fc1464c..85f2acd7727 100644 --- a/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart +++ b/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart @@ -511,6 +511,7 @@ void main() { }); } + // ignore: avoid-empty-test-groups, false positive. group('single span highlighting:', () { for (final spanText in modifierSpans) { testSingleSpan('modifier', spanText, modifierSyntaxColor); From a9a01d29e493551a54e52fa201bff6dc7ca2a208 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 16:49:54 -0700 Subject: [PATCH 10/16] use more specific errors and exceptions --- .../lib/src/screens/memory/panes/diff/data/classes_diff.dart | 2 +- .../devtools_app/lib/src/shared/charts/chart_controller.dart | 2 +- packages/devtools_app/lib/src/shared/console/console.dart | 2 +- packages/devtools_app/lib/src/shared/memory/class_name.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart b/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart index 031f5387758..a99474907bf 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/diff/data/classes_diff.dart @@ -45,7 +45,7 @@ class ObjectSetDiff { } if (kDebugMode) { - throw Exception( + throw StateError( 'Unexpected state for code $code: before=$before, after=$after', ); } diff --git a/packages/devtools_app/lib/src/shared/charts/chart_controller.dart b/packages/devtools_app/lib/src/shared/charts/chart_controller.dart index eff1df920f7..01364a4e6df 100644 --- a/packages/devtools_app/lib/src/shared/charts/chart_controller.dart +++ b/packages/devtools_app/lib/src/shared/charts/chart_controller.dart @@ -317,7 +317,7 @@ class ChartController extends DisposableController break; default: if (kDebugMode) { - throw Exception('Unexpected Duration $rangeInMinutes'); + throw ArgumentError('Unexpected Duration $rangeInMinutes'); } } } diff --git a/packages/devtools_app/lib/src/shared/console/console.dart b/packages/devtools_app/lib/src/shared/console/console.dart index bd365eee02f..618d3d7c127 100644 --- a/packages/devtools_app/lib/src/shared/console/console.dart +++ b/packages/devtools_app/lib/src/shared/console/console.dart @@ -206,7 +206,7 @@ class _ConsoleOutputState extends State<_ConsoleOutput> ); } else { if (kDebugMode) { - throw Exception( + throw UnsupportedError( 'ConsoleLine of unsupported type ${line.runtimeType} encountered', ); } diff --git a/packages/devtools_app/lib/src/shared/memory/class_name.dart b/packages/devtools_app/lib/src/shared/memory/class_name.dart index 271ad6efb9a..f9cd05a2395 100644 --- a/packages/devtools_app/lib/src/shared/memory/class_name.dart +++ b/packages/devtools_app/lib/src/shared/memory/class_name.dart @@ -167,7 +167,7 @@ class HeapClassName with Serializable { // or detect weak references automatically, without hard coding // class names. if (kDebugMode) { - throw Exception('Unexpected library for $className: $library.'); + throw StateError('Unexpected library for $className: $library.'); } return false; } From 84edcb42039432183b23263a7eb88dde3c33f361 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Fri, 31 Jul 2026 16:52:29 -0700 Subject: [PATCH 11/16] fix bug --- .../primitives/extent_delegate_list.dart | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart b/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart index e03599ace28..74bffe5e56b 100644 --- a/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart +++ b/packages/devtools_app/lib/src/shared/primitives/extent_delegate_list.dart @@ -344,22 +344,23 @@ class RenderSliverExtentDelegateBoxAdaptor extends RenderSliverMultiBoxAdaptor { collectGarbage(leadingGarbage, trailingGarbage); } else { collectGarbage(0, 0); + } - if (!addInitialChild( - index: firstIndex, - layoutOffset: _extentDelegate!.layoutOffset(firstIndex), - )) { - // There are either no children, or we are past the end of all our children. - // If it is the latter, we will need to find the first available child. - final max = _extentDelegate!.layoutOffset(childManager.childCount); - assert(max >= 0.0); - geometry = SliverGeometry( - scrollExtent: _extentDelegate!.layoutOffset(_extentDelegate!.length), - maxPaintExtent: max, - ); - childManager.didFinishLayout(); - return; - } + if (firstChild == null && + !addInitialChild( + index: firstIndex, + layoutOffset: _extentDelegate!.layoutOffset(firstIndex), + )) { + // There are either no children, or we are past the end of all our children. + // If it is the latter, we will need to find the first available child. + final max = _extentDelegate!.layoutOffset(childManager.childCount); + assert(max >= 0.0); + geometry = SliverGeometry( + scrollExtent: _extentDelegate!.layoutOffset(_extentDelegate!.length), + maxPaintExtent: max, + ); + childManager.didFinishLayout(); + return; } RenderBox? trailingChildWithLayout; From 6b542e0bfbbd6db11f7c9ec946920269df9fab75 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Mon, 3 Aug 2026 08:11:02 -0700 Subject: [PATCH 12/16] Use isTest annotation --- .../test/screens/debugger/syntax_highlighter_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart b/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart index 85f2acd7727..cbbbd105ebc 100644 --- a/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart +++ b/packages/devtools_app/test/screens/debugger/syntax_highlighter_test.dart @@ -18,6 +18,7 @@ import 'package:devtools_test/helpers.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:meta/meta.dart'; const modifierSpans = [ // Start multi-capture spans @@ -486,6 +487,7 @@ void main() { ); }); + @isTest void testSingleSpan( String name, String spanText, @@ -511,7 +513,6 @@ void main() { }); } - // ignore: avoid-empty-test-groups, false positive. group('single span highlighting:', () { for (final spanText in modifierSpans) { testSingleSpan('modifier', spanText, modifierSyntaxColor); From e0b1c19e6ede203eba65096e3bbc210eec5da48d Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Mon, 3 Aug 2026 09:17:17 -0700 Subject: [PATCH 13/16] fix issues --- .../lib/src/service/eval_on_dart_library.dart | 2 ++ packages/devtools_app_shared/test/test_utils.dart | 2 ++ packages/devtools_app_shared/test/ui/split_pane_test.dart | 1 + packages/devtools_shared/lib/src/test/chrome.dart | 2 +- .../test/helpers/extension_test_manager_test.dart | 2 -- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/devtools_app_shared/lib/src/service/eval_on_dart_library.dart b/packages/devtools_app_shared/lib/src/service/eval_on_dart_library.dart index 8df2f921353..234d45aee3f 100644 --- a/packages/devtools_app_shared/lib/src/service/eval_on_dart_library.dart +++ b/packages/devtools_app_shared/lib/src/service/eval_on_dart_library.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. +// ignore_for_file: avoid-duplicate-named-imports, used for easily prefixing Error without collision. + // This code is directly based on src/io/flutter/inspector/EvalOnDartLibrary.java // If you add a method to this class you should also add it to EvalOnDartLibrary.java import 'dart:async'; diff --git a/packages/devtools_app_shared/test/test_utils.dart b/packages/devtools_app_shared/test/test_utils.dart index 5a36b4ee05d..ca87fb39d5c 100644 --- a/packages/devtools_app_shared/test/test_utils.dart +++ b/packages/devtools_app_shared/test/test_utils.dart @@ -6,6 +6,7 @@ import 'package:devtools_app_shared/ui.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:meta/meta.dart'; // NOTE: these helpers are duplicated from `package:devtools_test`. We copied // them instead of importing `devtools_test`, because `devtools_test` is not @@ -28,6 +29,7 @@ Widget wrap(Widget widget) { } /// Runs a test with the size of the app window under test to [windowSize]. +@isTest void testWidgetsWithWindowSize( String name, Size windowSize, diff --git a/packages/devtools_app_shared/test/ui/split_pane_test.dart b/packages/devtools_app_shared/test/ui/split_pane_test.dart index 20827528950..e90968367ce 100644 --- a/packages/devtools_app_shared/test/ui/split_pane_test.dart +++ b/packages/devtools_app_shared/test/ui/split_pane_test.dart @@ -1217,6 +1217,7 @@ void main() { ); }, ); + testWidgetsWithWindowSize('return Axis.vertical', const Size(500, 800), ( WidgetTester tester, ) async { diff --git a/packages/devtools_shared/lib/src/test/chrome.dart b/packages/devtools_shared/lib/src/test/chrome.dart index 294385baaf5..ae8ff7bb0e3 100644 --- a/packages/devtools_shared/lib/src/test/chrome.dart +++ b/packages/devtools_shared/lib/src/test/chrome.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. -// ignore_for_file: avoid_print +// ignore_for_file: avoid_print, avoid-duplicate-named-imports, fix after moving file to package:dds. // DO NOT DELETE THIS FILE. It is imported by DDS and used in the // devtools_server tests. diff --git a/packages/devtools_shared/test/helpers/extension_test_manager_test.dart b/packages/devtools_shared/test/helpers/extension_test_manager_test.dart index e8101458fd9..96813679bdd 100644 --- a/packages/devtools_shared/test/helpers/extension_test_manager_test.dart +++ b/packages/devtools_shared/test/helpers/extension_test_manager_test.dart @@ -8,8 +8,6 @@ import 'package:test/test.dart'; import 'extension_test_manager.dart'; void main() { - group('$ExtensionTestManager', () {}); - group('$TestPackageWithExtension', () { test('$driftPackage', () { expect(driftPackage.name, 'drift'); From 67e5cd3d02e01e7af55e48e6d46939e5a1b3dc5e Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Tue, 15 Sep 2026 10:55:29 -0700 Subject: [PATCH 14/16] Upgrade DCM --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a82f49e4e23..fd28617023f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -75,7 +75,7 @@ jobs: wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list sudo apt-get update - sudo apt-get install dcm=1.38.3-1 # To avoid errors add `-1` (build number) to the version + sudo apt-get install dcm=1.39.1-1 # To avoid errors add `-1` (build number) to the version sudo chmod +x /usr/bin/dcm echo "$(dcm --version)" - name: Setup Dart SDK From a8194427ee3284a2be9ef4c78621db1360525804 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Tue, 15 Sep 2026 13:37:49 -0700 Subject: [PATCH 15/16] Fix a few lints --- .../accessibility_controller.dart | 12 +- .../screens/debugger/debugger_controller.dart | 1 - .../enhance_tracing/enhance_tracing.dart | 1 - .../vm_simple_list_display.dart | 1 - .../lib/src/shared/ui/common_widgets.dart | 2 +- .../shared/heap/heap_analyzer_test.dart | 1 - pubspec.lock | 180 ++++++++---------- 7 files changed, 84 insertions(+), 114 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/accessibility/accessibility_controller.dart b/packages/devtools_app/lib/src/screens/accessibility/accessibility_controller.dart index 573756a67aa..2c633fb7e6e 100644 --- a/packages/devtools_app/lib/src/screens/accessibility/accessibility_controller.dart +++ b/packages/devtools_app/lib/src/screens/accessibility/accessibility_controller.dart @@ -188,13 +188,11 @@ class AccessibilityController extends DevToolsScreenController } final roots = []; - if (rawData is Map) { - if (rawData.isNotEmpty) { - final rootId = rawData.containsKey('0') - ? '0' - : rawData.keys.first.toString(); - roots.add(_buildTreeFromNodesMap(rootId, rawData, {})); - } + if (rawData is Map && rawData.isNotEmpty) { + final rootId = rawData.containsKey('0') + ? '0' + : rawData.keys.first.toString(); + roots.add(_buildTreeFromNodesMap(rootId, rawData, {})); } if (roots.isEmpty) { diff --git a/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart b/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart index 01177d53466..485fed02bd8 100644 --- a/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart +++ b/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart @@ -402,7 +402,6 @@ class DebuggerController extends DevToolsScreenController /// cache, in order to reduce flashing in the editor view. void _populateScriptAndShowLocation(ScriptRef scriptRef) { safeUnawaited( - // ignore: avoid-async-call-in-sync-function, safeUnawaited handles this. scriptManager.getScript(scriptRef).then((script) async { await codeViewController.showScriptLocation(ScriptLocation(scriptRef)); }), diff --git a/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart b/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart index 8dd85f2351e..1e708a31f77 100644 --- a/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart +++ b/packages/devtools_app/lib/src/screens/performance/panes/controls/enhance_tracing/enhance_tracing.dart @@ -144,7 +144,6 @@ class _TraceWidgetBuildsSettingState extends State safeUnawaited( serviceConnection.serviceManager.serviceExtensionManager - // ignore: avoid-async-call-in-sync-function, safeUnawaited handles this. .waitForServiceExtensionAvailable(extension.extension) .then((isServiceAvailable) { if (isServiceAvailable) { diff --git a/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart b/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart index cedeaad9de0..4ebfa685dd3 100644 --- a/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart +++ b/packages/devtools_app/lib/src/screens/vm_developer/object_inspector/vm_simple_list_display.dart @@ -66,7 +66,6 @@ class _VmSimpleListDisplayState extends State { .value! .id!; final service = serviceConnection.serviceManager.service!; - // ignore: avoid-async-call-in-sync-function, intentional assignment of a future. _initialized = service.getObject(isolateId, elementsInstance.id!); unawaited( _initialized.then( diff --git a/packages/devtools_app/lib/src/shared/ui/common_widgets.dart b/packages/devtools_app/lib/src/shared/ui/common_widgets.dart index 7d191ec2400..d26a6cb4487 100644 --- a/packages/devtools_app/lib/src/shared/ui/common_widgets.dart +++ b/packages/devtools_app/lib/src/shared/ui/common_widgets.dart @@ -947,7 +947,7 @@ class _JsonViewerState extends State { ); // Creates tree structure } // Intended to be unawaited. - // ignore: discarded_futures, avoid-async-call-in-sync-function + // ignore: discarded_futures _initializeTree = _buildAndExpand(variable); } diff --git a/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart b/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart index 05541973783..45e96c3aa81 100644 --- a/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart +++ b/packages/devtools_app/test/screens/memory/shared/heap/heap_analyzer_test.dart @@ -15,7 +15,6 @@ void main() { final heap = HeapData(t.heap, created: DateTime.now()); await heap.calculate; - // ignore: avoid-accessing-collections-by-constant-index, intentional use of special index. expect(heap.retainedSizes![heapRootIndex], equals(t.rootRetainedSize)); var actualUnreachableSize = 0; diff --git a/pubspec.lock b/pubspec.lock index c2fa2b744ff..0eddb643472 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d + sha256: "1b0e6a07425a3e460666e88bf1c949ccc7bb0116ad562ce94a1eca60fe820725" url: "https://pub.dev" source: hosted - version: "91.0.0" + version: "103.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 + sha256: "61c04d0c1bfed555c681ea079519933f071a5a026578ff73c4ff0df2d3462e5e" url: "https://pub.dev" source: hosted - version: "8.4.1" + version: "13.3.0" archive: dependency: transitive description: name: archive - sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + sha256: "6c5bcd986e06b94e3c40244af471750840a3d2341d1f9763a1100a14add517b4" url: "https://pub.dev" source: hosted - version: "4.0.9" + version: "4.3.0" args: dependency: transitive description: @@ -61,34 +61,34 @@ packages: dependency: transitive description: name: build - sha256: "45d14a0fb23e018d8287c32fc98d726ce466b231928ed9b9200f29bd3ccd39ae" + sha256: "8a5c5761af8e31748bba3c82f68925ace40f3225c3eea25be9beb57eca7cd7a8" url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.0.11" build_config: dependency: transitive description: name: build_config - sha256: "94eaf6708fe64408c632ef2689ca3777b112f9421306ccf4f8c84d7c5c9f83f8" + sha256: d466ed2dc9c6cd1d169948879b84ee061eb5e22c64a7c6089879c6296d272a8d url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" build_daemon: dependency: transitive description: name: build_daemon - sha256: "8c0535c3b2f625619f4dd1036ef1127f2e77bfedf89ed2eb2676ef076e0b6712" + sha256: e1d40ef3f7934986d5da2271b1ba07794921ce263e44d622fb6c406d76589e33 url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "4.1.6" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "5367e521935b102bdf1e735d2aab461e36b2edca6517662d088dd04cc39f8d16" + sha256: "894c243f6bc32015fec466ce30a6925bd537a77a426ee5bf481120477eb3de67" url: "https://pub.dev" source: hosted - version: "2.15.1" + version: "2.16.1" built_collection: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: built_value - sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56" + sha256: f87ea98192116f7093cb214551ce1929caae0681fdba282b3d8b4462adee7bb7 url: "https://pub.dev" source: hosted - version: "8.12.6" + version: "8.13.0" characters: dependency: transitive description: @@ -141,18 +141,18 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" code_builder: dependency: transitive description: name: code_builder - sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + sha256: aa5932e94c6c39c2f9ec4e5e06dfdd11a9430a61f6c41b6ba75b28ce0c481baf url: "https://pub.dev" source: hosted - version: "4.11.1" + version: "4.12.0" collection: dependency: transitive description: @@ -181,10 +181,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "92c9c43c383bfa1c32079d3bc492d55d6d4318044b7b47edaff8971cbb555c51" + sha256: f141ea4f277af142a0356955707f6556f37b03947d39d55585981a06ca437bd6 url: "https://pub.dev" source: hosted - version: "0.3.5+4" + version: "0.3.5+5" crypto: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: dart_style - sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b + sha256: "82ade9fc4273f29ed673e33166944465225b4f7fc5d4aaef48605cc751c18fc1" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.13" dds_service_extensions: dependency: transitive description: @@ -277,34 +277,34 @@ packages: dependency: transitive description: name: file_selector_android - sha256: "1d45e9910f68c16eb0c74f0b10097ad81aed516ea28054c027137e8f7d75e840" + sha256: d670cd0ce77a2e785b18d8b4d0a8d6a222d6a813ec9b7ddf2790a1b4fb6fa92c url: "https://pub.dev" source: hosted - version: "0.5.2+9" + version: "0.5.2+11" file_selector_ios: dependency: transitive description: name: file_selector_ios - sha256: e2ecf2885c121691ce13b60db3508f53c01f869fb6e8dc5c1cfa771e4c46aeca + sha256: "97269e5307a0ab813b1fa2430bada0a96e0afb74848417f8676f64ba5de0051c" url: "https://pub.dev" source: hosted - version: "0.5.3+5" + version: "0.5.3+6" file_selector_linux: dependency: transitive description: name: file_selector_linux - sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + sha256: da76400e7872ce7637ffdce12749ec24169c25f6195c28372208e65a24bcd2ab url: "https://pub.dev" source: hosted - version: "0.9.4" + version: "0.9.4+1" file_selector_macos: dependency: transitive description: name: file_selector_macos - sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + sha256: d57c62362766b5e7ae739448650b66c6aab7a68ba7ecc65e04018652645ae0f4 url: "https://pub.dev" source: hosted - version: "0.9.5" + version: "0.9.5+1" file_selector_platform_interface: dependency: transitive description: @@ -325,10 +325,10 @@ packages: dependency: transitive description: name: file_selector_windows - sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + sha256: fbefc5fb92c6d3cbe8d284a2cd971b593bb07d2cd6da8557b81a862250b4acec url: "https://pub.dev" source: hosted - version: "0.9.3+5" + version: "0.9.3+6" fixnum: dependency: transitive description: @@ -397,10 +397,10 @@ packages: dependency: transitive description: name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + sha256: "218aeb56050c714f62a3182775320dfa04602b55074873e24e31bbd39bda96fb" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.0" graphs: dependency: transitive description: @@ -437,10 +437,10 @@ packages: dependency: transitive description: name: image - sha256: "6300175e00616bbc832e2fc91bfa4d776af5402c81c7151bee6905bb08473c52" + sha256: a1e7f4951e538a568e14b856702afc9ae1d2f4b202daced8d22c1b9cd211ce89 url: "https://pub.dev" source: hosted - version: "4.9.1" + version: "4.10.1" integration_test: dependency: transitive description: flutter @@ -458,10 +458,10 @@ packages: dependency: transitive description: name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + sha256: "2635216ca6a737e60de577ffa1a48a0bec76ca8a62917cfc1bb88c14c570646f" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.1.0" json_annotation: dependency: transitive description: @@ -510,14 +510,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" - listen: - dependency: transitive - description: - name: listen - sha256: "47501a08016a43fcad79252439d723f50f14f88fa7bfd8a177e0a417e5c9e1f2" - url: "https://pub.dev" - source: hosted - version: "1.0.1" logging: dependency: transitive description: @@ -562,18 +554,18 @@ packages: dependency: transitive description: name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + sha256: bd47de35f07e27267e69c8c8b22edf9473bfee170a60d60fcc93730c5144b7f6 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.0" mockito: dependency: transitive description: name: mockito - sha256: eff30d002f0c8bf073b6f929df4483b543133fcafce056870163587b03f1d422 + sha256: "6c1970612452260366064d4df80fdb3eece1ec5e52610ae34a0e51f2f3d8e64f" url: "https://pub.dev" source: hosted - version: "5.6.4" + version: "5.8.1" nested: dependency: transitive description: @@ -613,22 +605,14 @@ packages: relative: true source: path version: "0.0.1" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" - url: "https://pub.dev" - source: hosted - version: "7.0.2" platform: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + sha256: a36d119c13416516a7b5913fbe8af8531e11633d784c550b2125f76c758524ec url: "https://pub.dev" source: hosted - version: "3.1.6" + version: "3.2.0" plugin_platform_interface: dependency: transitive description: @@ -641,10 +625,10 @@ packages: dependency: transitive description: name: pointer_interceptor - sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523" + sha256: "9ad8889f36a417649ad7578fdb6df967157208cb90f69facd043660424020710" url: "https://pub.dev" source: hosted - version: "0.10.1+2" + version: "0.10.1+3" pointer_interceptor_ios: dependency: transitive description: @@ -673,10 +657,10 @@ packages: dependency: transitive description: name: pool - sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + sha256: "4177f68c237ea2128d1bee66ac17b2ce05ba3dbaafcbdd54c5d40a39d0b6b11c" url: "https://pub.dev" source: hosted - version: "1.5.2" + version: "1.5.3" posix: dependency: transitive description: @@ -689,10 +673,10 @@ packages: dependency: transitive description: name: process - sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + sha256: "4242ba3508d37e01808bdf71ad1d5bb93a8d671bf2e7450e6b1b353fb0808891" url: "https://pub.dev" source: hosted - version: "5.0.5" + version: "5.0.6" protobuf: dependency: transitive description: @@ -713,18 +697,18 @@ packages: dependency: transitive description: name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + sha256: "261236774e8b1d69cfc6b9eabbc96c40f25e7a2d6b171f3385d4f65d5734fb24" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + sha256: c38b81cbf34450b67e0265d73433569d12e34782e30ed769c9cc99c9d5f2e796 url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.6.0" shelf: dependency: transitive description: @@ -790,10 +774,10 @@ packages: dependency: transitive description: name: source_maps - sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + sha256: "14c2945847669b44089bb1222f66873d7ff7103c58911917f2a63c5a62327898" url: "https://pub.dev" source: hosted - version: "0.10.13" + version: "0.10.14" source_span: dependency: transitive description: @@ -814,18 +798,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "277654b3034d17ac6f9f1cb5595db011b1d5d41e8806866db28e0abaa101c490" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.12.2" stager: dependency: transitive description: name: stager - sha256: "2782efb6057d9c391d96ef0e9714a0a3e02d311e7dd376448e3a87e4e87ac8f1" + sha256: c3b8bf30a2b02152a1125bb6fedf0d6f52fb0b154bd97854cb3e9cc59be975ad url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" stream_channel: dependency: transitive description: @@ -838,10 +822,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + sha256: a00e5f18bffc764f923e7dec1038527f7fe7a1791361a7117f0358193f13d53a url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -918,34 +902,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: b413d49b73867ac08dd2f9890efd3cc11f2a0e577618d50843440a1fb3776c32 + sha256: "611e87fb320b70d1dd721dc46af89c98aceccea9b31fde49e084591414e0c610" url: "https://pub.dev" source: hosted - version: "6.3.32" + version: "6.3.33" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + sha256: "8faa1aab294f1ab4040b43660c887b0418d5fa4f0cffef76a484e6aa1092eb4a" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.4.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + sha256: "10f86fef4c2c43563fa6c211ff9cf757adf4d3ab762c56bd430664a947d70cd0" url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.2.3" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + sha256: "5e835a3b869c2d70325349c81c5a45c28e20791265b67b2669da6b08c5cd5201" url: "https://pub.dev" source: hosted - version: "3.2.5" + version: "3.2.6" url_launcher_platform_interface: dependency: transitive description: @@ -966,10 +950,10 @@ packages: dependency: transitive description: name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + sha256: "6c5ad3f22cd4c38e089b81963b3cd7bb83b111b2df5dce008bb066162f42e429" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" vector_math: dependency: transitive description: @@ -1046,10 +1030,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + sha256: "28b82ec894fed45dd71c23ba62d1af973ed97dd59a4f5790a4d38b0b13e5657e" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.0" webkit_inspection_protocol: dependency: transitive description: @@ -1058,22 +1042,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" - xml: - dependency: transitive - description: - name: xml - sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4" - url: "https://pub.dev" - source: hosted - version: "7.0.1" yaml: dependency: transitive description: name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + sha256: f67cdd8e07d3c6329146aaef1ba043542b3134c12489f553ca9a7435d1068aea url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" yaml_edit: dependency: transitive description: From 5f5f83fb7588bcb899fc1f516a177efda5c21ba5 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson Date: Tue, 15 Sep 2026 14:12:47 -0700 Subject: [PATCH 16/16] Fix logic bug --- packages/devtools_app/lib/src/shared/ui/search.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/ui/search.dart b/packages/devtools_app/lib/src/shared/ui/search.dart index d74974854fa..312da17ed1f 100644 --- a/packages/devtools_app/lib/src/shared/ui/search.dart +++ b/packages/devtools_app/lib/src/shared/ui/search.dart @@ -1250,10 +1250,10 @@ class _AutoCompleteSearchFieldState extends State } // Nothing found, pick item selected in dropdown. final autoCompleteList = widget.controller.searchAutoComplete.value; - if (autoCompleteList.isNotEmpty && foundExact == null || + if (autoCompleteList.isNotEmpty && (foundExact == null || autoCompleteList[widget.controller.currentHoveredIndex.value] .text != - foundExact) { + foundExact)) { foundExact = autoCompleteList[widget.controller.currentHoveredIndex.value] .text;