From 0635092f1c17103f0ef0a5dcaf33bb95bd1503af Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Thu, 22 May 2025 12:24:59 -0700 Subject: [PATCH 1/3] Fix copying issue for inspector nodes --- .../shared/diagnostics/dart_object_node.dart | 27 ++++++++++++++++--- .../macos/Runner.xcodeproj/project.pbxproj | 6 ++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart index b7279fb7b9f..1fa9243d6da 100644 --- a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart +++ b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart @@ -372,11 +372,30 @@ class DartObjectNode extends TreeNode { String toString() { if (text != null) return text!; + // If the name is provided, use it followed by the instanceRef. final instanceRef = ref!.instanceRef; - final value = instanceRef is InstanceRef - ? instanceRef.valueAsString - : instanceRef; - return '$name - $value'; + if ((name ?? '').isNotEmpty) { + final value = instanceRef is InstanceRef + ? instanceRef.valueAsString + : instanceRef; + return '$name - $value'; + } + + // Use the diagnostics node (if it exists). This is only provided for + // Inspector nodes. + final diagnostic = ref?.diagnostic; + final description = diagnostic?.description; + if (diagnostic != null && description != null) { + final separator = diagnostic.separator; + final textPreview = diagnostic.json['textPreview']; + return textPreview != null + ? '$description$separator $textPreview' + : description; + } + + // Fallback to returning the instanceRef as a String if none of the above + // cases are true. + return instanceRef.toString(); } /// Selects the object in the Flutter Widget inspector. diff --git a/packages/devtools_app/macos/Runner.xcodeproj/project.pbxproj b/packages/devtools_app/macos/Runner.xcodeproj/project.pbxproj index e9c8ca8c9dc..59aa8f360ec 100644 --- a/packages/devtools_app/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/devtools_app/macos/Runner.xcodeproj/project.pbxproj @@ -553,7 +553,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -632,7 +632,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -679,7 +679,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; From 0782adf5c42e358cab9e9c8be3026dce2c7cdd60 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Thu, 22 May 2025 16:37:57 -0700 Subject: [PATCH 2/3] Add tests --- .../shared/diagnostics/dart_object_node.dart | 17 ++-- .../diagnostics/dart_object_node_test.dart | 37 +++++++++ .../test/test_infra/utils/variable_utils.dart | 79 ++++++++++++++++++- 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart index 1fa9243d6da..8aa7d985549 100644 --- a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart +++ b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart @@ -374,11 +374,13 @@ class DartObjectNode extends TreeNode { // If the name is provided, use it followed by the instanceRef. final instanceRef = ref!.instanceRef; - if ((name ?? '').isNotEmpty) { - final value = instanceRef is InstanceRef - ? instanceRef.valueAsString - : instanceRef; - return '$name - $value'; + if (instanceRef != null && (name ?? '').isNotEmpty) { + final length = instanceRef.length; + if (instanceRef.length != null) { + return '$name - ${instanceRef.kind} ($length)'; + } + + return '$name - ${instanceRef.valueAsString}'; } // Use the diagnostics node (if it exists). This is only provided for @@ -393,9 +395,8 @@ class DartObjectNode extends TreeNode { : description; } - // Fallback to returning the instanceRef as a String if none of the above - // cases are true. - return instanceRef.toString(); + // Fallback to returning the runtime type as a catch-all. + return ref.runtimeType.toString(); } /// Selects the object in the Flutter Widget inspector. diff --git a/packages/devtools_app/test/shared/diagnostics/dart_object_node_test.dart b/packages/devtools_app/test/shared/diagnostics/dart_object_node_test.dart index 675dbc9b6ce..95be5046d8a 100644 --- a/packages/devtools_app/test/shared/diagnostics/dart_object_node_test.dart +++ b/packages/devtools_app/test/shared/diagnostics/dart_object_node_test.dart @@ -105,4 +105,41 @@ void main() { expect(str.childCount, equals(0)); expect(str.isPartialObject, isFalse); }); + + group('toString', () { + test('string variable', () { + final str = buildStringVariable('Hello there!'); + expect(str.toString(), equals('root1 - Hello there!')); + }); + + test('boolean variable', () { + final boolean = buildBooleanVariable(true); + expect(boolean.toString(), equals('root1 - true')); + }); + + test('set variable', () { + final set = buildSetVariable(length: 3); + expect(set.toString(), equals('root1 - Set (3)')); + }); + + test('map variable', () { + final map = buildMapVariable(length: 3); + expect(map.toString(), equals('root1 - Map (3)')); + }); + + test('string variable', () { + final list = buildListVariable(length: 3); + expect(list.toString(), equals('root1 - List (3)')); + }); + + testWidgets('Text widget', (WidgetTester tester) async { + final textWidget = buildTextWidgetVariable(); + expect(textWidget.toString(), equals('Text: Hello world!')); + }); + + testWidgets('Row widget', (WidgetTester tester) async { + final rowWidget = buildRowWidgetVariable(); + expect(rowWidget.toString(), equals('Row')); + }); + }); } diff --git a/packages/devtools_app/test/test_infra/utils/variable_utils.dart b/packages/devtools_app/test/test_infra/utils/variable_utils.dart index 5202a449c00..1515c977ff9 100644 --- a/packages/devtools_app/test/test_infra/utils/variable_utils.dart +++ b/packages/devtools_app/test/test_infra/utils/variable_utils.dart @@ -2,7 +2,10 @@ // 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:convert'; + import 'package:devtools_app/src/shared/diagnostics/dart_object_node.dart'; +import 'package:devtools_app/src/shared/diagnostics/diagnostics_node.dart'; import 'package:devtools_app/src/shared/diagnostics/generic_instance_reference.dart'; import 'package:vm_service/vm_service.dart'; @@ -213,6 +216,22 @@ DartObjectNode buildBooleanVariable(bool value) { ); } +DartObjectNode buildTextWidgetVariable() { + return DartObjectNode.fromValue( + value: null, + isolateRef: _isolateRef, + diagnostic: _textWidgetDiagnosticNode, + ); +} + +DartObjectNode buildRowWidgetVariable() { + return DartObjectNode.fromValue( + value: null, + isolateRef: _isolateRef, + diagnostic: _rowWidgetDiagnosticNode, + ); +} + InstanceRef _buildInstanceRefForMap({required int length}) => InstanceRef( id: _incrementRef(), kind: InstanceKind.kMap, @@ -266,5 +285,63 @@ int _rootNumber = 0; String _incrementRoot() { _rootNumber++; - return 'Root $_rootNumber'; + return 'root$_rootNumber'; +} + +final _textWidgetDiagnosticNode = RemoteDiagnosticsNode( + jsonDecode(_textWidgetDiagnosticJson), + null, + false, + null, +); + +final _rowWidgetDiagnosticNode = RemoteDiagnosticsNode( + jsonDecode(_rowWidgetDiagnosticJson), + null, + false, + null, +); + +const _textWidgetDiagnosticJson = ''' +{ + "description": "Text", + "type": "_ElementDiagnosticableTreeNode", + "style": "dense", + "hasChildren": true, + "allowWrap": false, + "summaryTree": true, + "locationId": 0, + "creationLocation": { + "file": "file:///Users/prismo/flutter_app/main.dart", + "line": 109, + "column": 23, + "name": "Text" + }, + "createdByLocalProject": true, + "textPreview": "Hello world!", + "children": [], + "widgetRuntimeType": "Text", + "stateful": false +} +'''; + +const _rowWidgetDiagnosticJson = ''' +{ + "description": "Row", + "type": "_ElementDiagnosticableTreeNode", + "hasChildren": true, + "allowWrap": false, + "summaryTree": true, + "locationId": 0, + "creationLocation": { + "file": "file:///Users/prismo/flutter_app/main.dart", + "line": 109, + "column": 23, + "name": "Row" + }, + "createdByLocalProject": true, + "children": [], + "widgetRuntimeType": "Row", + "stateful": false } +'''; From 35eea563c72eebd36c29a4a20357def989785d2e Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Thu, 22 May 2025 16:45:25 -0700 Subject: [PATCH 3/3] Update comments --- .../lib/src/shared/diagnostics/dart_object_node.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart index 8aa7d985549..70afeb226d6 100644 --- a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart +++ b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart @@ -372,14 +372,17 @@ class DartObjectNode extends TreeNode { String toString() { if (text != null) return text!; - // If the name is provided, use it followed by the instanceRef. final instanceRef = ref!.instanceRef; if (instanceRef != null && (name ?? '').isNotEmpty) { final length = instanceRef.length; + // Show the variable name, kind, and length for instance kinds that have a + // length (maps, lists, sets, etc). if (instanceRef.length != null) { return '$name - ${instanceRef.kind} ($length)'; } + // Show the variable name and value for instance kinds without a length + //(e.g. strings, booleans, ints). return '$name - ${instanceRef.valueAsString}'; }