From 464641f51af0416df9ec0138d9e0d523deef0206 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Wed, 8 Jul 2020 01:49:40 +0000 Subject: [PATCH] Extend BaselPackageUriResolver to handle files outside of `lib`. Generated files can exist outside of `lib`. In a Bazel workspace these are referred to using `file:` URIs that point to the generated code directory. We need to be able to resolve references both from the generated code to non-generated code and vice versa. This is blocking the use of the migration tool in Bazel workspaces, since the migration tool doesn't have the same level of error recovery as the rest of the analyzer, so it needs to be able to resolve all files including generated ones. But it should also improve the user experience for using the analysis server in general in Bazel workspaces, by reducing the number of nuisance "URI not resolved" errors. Change-Id: I38dababd29f4490746cc6e1eeede9f438526a815 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153520 Reviewed-by: Konstantin Shcheglov Commit-Queue: Paul Berry --- pkg/analyzer/lib/src/workspace/bazel.dart | 33 +++++++++++ .../test/src/workspace/bazel_test.dart | 57 +++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart index 5b6bd923c20e..22e4b567fe94 100644 --- a/pkg/analyzer/lib/src/workspace/bazel.dart +++ b/pkg/analyzer/lib/src/workspace/bazel.dart @@ -59,6 +59,13 @@ class BazelPackageUriResolver extends UriResolver { @override Source resolveAbsolute(Uri uri, [Uri actualUri]) { return _sourceCache.putIfAbsent(uri, () { + if (uri.scheme == 'file') { + var pathRelativeToRoot = _workspace._relativeToRoot(uri.path); + if (pathRelativeToRoot == null) return null; + var fullFilePath = _context.join(_workspace.root, pathRelativeToRoot); + File file = _workspace.findFile(fullFilePath); + return file?.createSource(uri); + } if (uri.scheme != 'package') { return null; } @@ -306,6 +313,32 @@ class BazelWorkspace extends Workspace } } + String _relativeToRoot(String p) { + path.Context context = provider.pathContext; + // genfiles + if (genfiles != null && context.isWithin(genfiles, p)) { + return context.relative(p, from: genfiles); + } + // bin + for (String bin in binPaths) { + if (context.isWithin(bin, p)) { + return context.relative(p, from: bin); + } + } + // READONLY + if (readonly != null) { + if (context.isWithin(readonly, p)) { + return context.relative(p, from: readonly); + } + } + // Not generated + if (context.isWithin(root, p)) { + return context.relative(p, from: root); + } + // Failed reverse lookup + return null; + } + /// Find the Bazel workspace that contains the given [filePath]. /// /// This method walks up the file system from [filePath], looking for various diff --git a/pkg/analyzer/test/src/workspace/bazel_test.dart b/pkg/analyzer/test/src/workspace/bazel_test.dart index f267f85205b4..6bc5fb90ae3b 100644 --- a/pkg/analyzer/test/src/workspace/bazel_test.dart +++ b/pkg/analyzer/test/src/workspace/bazel_test.dart @@ -130,6 +130,58 @@ class BazelPackageUriResolverTest with ResourceProviderMixin { exists: true); } + void test_resolveAbsolute_file_bin_to_genfiles() { + _addResources([ + '/workspace/WORKSPACE', + '/workspace/bazel-genfiles/my/foo/test/foo1.dart', + '/workspace/bazel-bin/' + ]); + _assertResolve('file:///workspace/bazel-bin/my/foo/test/foo1.dart', + '/workspace/bazel-genfiles/my/foo/test/foo1.dart', + restore: false); + } + + void test_resolveAbsolute_file_genfiles_to_workspace() { + _addResources([ + '/workspace/WORKSPACE', + '/workspace/bazel-genfiles/', + '/workspace/my/foo/test/foo1.dart' + ]); + _assertResolve('file:///workspace/bazel-genfiles/my/foo/test/foo1.dart', + '/workspace/my/foo/test/foo1.dart', + restore: false); + } + + void test_resolveAbsolute_file_not_in_workspace() { + _addResources([ + '/workspace/WORKSPACE', + '/workspace/bazel-genfiles/', + '/other/my/foo/test/foo1.dart' + ]); + _assertNoResolve('file:///other/my/foo/test/foo1.dart'); + } + + void test_resolveAbsolute_file_readonly_to_workspace() { + _addResources([ + '/workspace/WORKSPACE', + '/READONLY/workspace/', + '/workspace/my/foo/test/foo1.dart' + ]); + _assertResolve('file:///READONLY/workspace/my/foo/test/foo1.dart', + '/workspace/my/foo/test/foo1.dart', + restore: false); + } + + void test_resolveAbsolute_file_workspace_to_genfiles() { + _addResources([ + '/workspace/WORKSPACE', + '/workspace/bazel-genfiles/my/foo/test/foo1.dart' + ]); + _assertResolve('file:///workspace/my/foo/test/foo1.dart', + '/workspace/bazel-genfiles/my/foo/test/foo1.dart', + restore: false); + } + void test_resolveAbsolute_genfiles() { _addResources([ '/workspace/WORKSPACE', @@ -465,6 +517,11 @@ class BazelPackageUriResolverTest with ResourceProviderMixin { resolver = BazelPackageUriResolver(workspace); } + void _assertNoResolve(String uriStr) { + var uri = Uri.parse(uriStr); + expect(resolver.resolveAbsolute(uri), isNull); + } + void _assertResolve(String uriStr, String posixPath, {bool exists = true, bool restore = true}) { Uri uri = Uri.parse(uriStr);