Fix project directory inference for inspector panel (#6857)
Fixes https://github.com/flutter/devtools/issues/6841, https://github.com/flutter/devtools/issues/6853
Instead of using the top level widget in the widget tree to determine the project directory, we instead use the main isolate's root library.
For google3, we also have extra logic to strip out everything before `/google3`, and to only use top-level directory after `google3` directory (or the top-level directory after `third_party`)
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 3f45982..df95586 100644
--- a/packages/devtools_app/lib/src/shared/diagnostics/inspector_service.dart
+++ b/packages/devtools_app/lib/src/shared/diagnostics/inspector_service.dart
@@ -27,7 +27,10 @@
import 'primitives/instance_ref.dart';
import 'primitives/source_location.dart';
-const inspectorLibraryUri = 'package:flutter/src/widgets/widget_inspector.dart';
+const _inspectorLibraryUri =
+ 'package:flutter/src/widgets/widget_inspector.dart';
+const _google3PathSegment = 'google3';
+const _thirdPartyPathSegment = 'third_party';
abstract class InspectorServiceBase extends DisposableController
with AutoDisposeControllerMixin {
@@ -183,7 +186,7 @@
: super(
clientInspectorName: 'WidgetInspectorService',
serviceExtensionPrefix: inspectorExtensionPrefix,
- inspectorLibraryUri: inspectorLibraryUri,
+ inspectorLibraryUri: _inspectorLibraryUri,
evalIsolate:
serviceConnection.serviceManager.isolateManager.mainIsolate,
) {
@@ -339,9 +342,8 @@
final libIndex = parts.lastIndexOf('lib');
final path = libIndex > 0 ? parts.sublist(0, libIndex) : parts;
// Special case handling of bazel packages.
- final google3Index = path.lastIndexOf('google3');
- if (google3Index != -1 && google3Index + 1 < path.length) {
- var packageParts = path.sublist(google3Index + 1);
+ if (_isGoogle3Path(path)) {
+ var packageParts = _stripGoogle3(path);
// A well formed third_party dart package should be in a directory of
// the form
// third_party/dart/packageName (package:packageName)
@@ -483,60 +485,69 @@
}
Future<String?> inferPubRootDirectoryIfNeededHelper() async {
- final group = createObjectGroup('temp');
- final root = await group.getRoot(FlutterTreeType.widget);
-
- if (root == null) {
- // No need to do anything as there isn't a valid tree (yet?).
- await group.dispose();
- return null;
- }
- List<RemoteDiagnosticsNode?> children = await root.children ?? [];
-
- if (children.isEmpty) {
- children = await group.getChildren(root.valueRef, false, null);
- }
-
- if (children.isEmpty) {
- await group.dispose();
- return null;
- }
- final path = children.first!.creationLocation?.path;
+ final path = await serviceConnection.rootLibraryForMainIsolate();
if (path == null) {
- await group.dispose();
return null;
}
- // TODO(jacobr): it would be nice to use Isolate.rootLib similar to how
- // debugger.dart does but we are currently blocked by the
- // --track-widget-creation transformer generating absolute paths instead of
- // package:paths.
- // Once https://github.com/flutter/flutter/issues/26615 is fixed we will be
- // able to use package: paths. Temporarily all tools tracking widget
- // locations will need to support both path formats.
+ // TODO(jacobr): Once https://github.com/flutter/flutter/issues/26615 is
+ // fixed we will be able to use package: paths. Temporarily all tools
+ // tracking widget locations will need to support both path formats.
// TODO(jacobr): use the list of loaded scripts to determine the appropriate
// package root directory given that the root script of this project is in
// this directory rather than guessing based on url structure.
final parts = path.split('/');
String? pubRootDirectory;
- for (int i = parts.length - 1; i >= 0; i--) {
- final part = parts[i];
- if (part == 'lib' || part == 'web') {
- pubRootDirectory = parts.sublist(0, i).join('/');
- break;
- }
+ // For google3, we grab the top-level directory in the google3 directory
+ // (e.g. /education), or the top-level directory in third_party (e.g.
+ // /third_party/dart):
+ if (_isGoogle3Path(parts)) {
+ pubRootDirectory = _pubRootDirectoryForGoogle3(parts);
+ } else {
+ final parts = path.split('/');
- if (part == 'packages') {
- pubRootDirectory = parts.sublist(0, i + 1).join('/');
- break;
+ for (int i = parts.length - 1; i >= 0; i--) {
+ final part = parts[i];
+ if (part == 'lib' || part == 'web') {
+ pubRootDirectory = parts.sublist(0, i).join('/');
+ break;
+ }
+
+ if (part == 'packages') {
+ pubRootDirectory = parts.sublist(0, i + 1).join('/');
+ break;
+ }
}
}
pubRootDirectory ??= (parts..removeLast()).join('/');
await _addPubRootDirectories([pubRootDirectory]);
- await group.dispose();
return pubRootDirectory;
}
+ bool _isGoogle3Path(List<String> pathParts) =>
+ pathParts.contains(_google3PathSegment);
+
+ List<String> _stripGoogle3(List<String> pathParts) {
+ final google3Index = pathParts.lastIndexOf(_google3PathSegment);
+ if (google3Index != -1 && google3Index + 1 < pathParts.length) {
+ return pathParts.sublist(google3Index + 1);
+ }
+ return pathParts;
+ }
+
+ String? _pubRootDirectoryForGoogle3(List<String> pathParts) {
+ final strippedParts = _stripGoogle3(pathParts);
+ if (strippedParts.isEmpty) return null;
+
+ final topLevelDirectory = strippedParts.first;
+ if (topLevelDirectory == _thirdPartyPathSegment &&
+ strippedParts.length >= 2) {
+ return '/${strippedParts.sublist(0, 2).join('/')}';
+ } else {
+ return '/${strippedParts.first}';
+ }
+ }
+
RemoteDiagnosticsNode? _currentSelection;
InspectorObjectGroupManager get _selectionGroups {
diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
index 6773632..7a81a35 100644
--- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
+++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
@@ -15,6 +15,8 @@
## Inspector updates
* Added link to package directory documentation, from the inspect settings dialog - [6825](https://github.com/flutter/devtools/pull/6825)
+* Fix bug where widgets owned by the Flutter framework were showing up in the widget tree view -
+[6857](https://github.com/flutter/devtools/pull/6857)
## Performance updates
diff --git a/packages/devtools_app/test/inspector/inspector_service_test.dart b/packages/devtools_app/test/inspector/inspector_service_test.dart
index 44d93b5..0579a9e 100644
--- a/packages/devtools_app/test/inspector/inspector_service_test.dart
+++ b/packages/devtools_app/test/inspector/inspector_service_test.dart
@@ -17,6 +17,10 @@
import '../test_infra/flutter_test_environment.dart';
import '../test_infra/matchers/matchers.dart';
+// TODO(elliette): Add testing that project directories can be inferred from
+// google3-paths. This will require mocking the main isolate so that we can
+// change the root library during testing instead of using the
+// LiveTestWidgetsFlutterBinding.
void main() {
initializeLiveTestWidgetsFlutterBindingWithAssets();
@@ -82,6 +86,9 @@
await env.tearDownEnvironment(force: true);
});
+ // TODO(elliette): Figure out why this didn't catch
+ // https://github.com/flutter/devtools/issues/6841 and fix so that it
+ // catches future regressions.
test('can be inferred', () async {
await env.setupEnvironment();
final inspectorServiceLocal = inspectorService!;