aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-12-09 16:07:33 +0000
committerGitHub <[email protected]>2020-12-09 16:07:33 +0000
commit99118eeccdf6564876bbe6ec0672b04ffcbe3442 (patch)
tree08f0fd7d99ad22a3d1db782482b66548e99ba8b2 /crates
parent42be522c80cf0cc2d49b60f3c1d66afdc51fcbbb (diff)
parent6e24321e4579d25686982002ed18f321db23cb9f (diff)
Merge #6784
6784: Introduce anchored_path r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/base_db/src/lib.rs15
-rw-r--r--crates/hir_def/src/nameres/mod_resolution.rs5
-rw-r--r--crates/hir_def/src/test_db.rs6
-rw-r--r--crates/hir_expand/src/builtin_macro.rs5
-rw-r--r--crates/hir_expand/src/test_db.rs6
-rw-r--r--crates/hir_ty/src/test_db.rs8
-rw-r--r--crates/ide/src/diagnostics.rs10
-rw-r--r--crates/ide/src/diagnostics/fixes.rs8
-rw-r--r--crates/ide/src/references/rename.rs57
-rw-r--r--crates/ide_db/src/lib.rs8
-rw-r--r--crates/ide_db/src/source_change.rs6
-rw-r--r--crates/rust-analyzer/src/global_state.rs7
-rw-r--r--crates/rust-analyzer/src/to_proto.rs8
-rw-r--r--crates/vfs/src/anchored_path.rs39
-rw-r--r--crates/vfs/src/file_set.rs8
-rw-r--r--crates/vfs/src/lib.rs6
16 files changed, 130 insertions, 72 deletions
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index 5571af495..595f28ada 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -18,7 +18,7 @@ pub use crate::{
18 }, 18 },
19}; 19};
20pub use salsa; 20pub use salsa;
21pub use vfs::{file_set::FileSet, FileId, VfsPath}; 21pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};
22 22
23#[macro_export] 23#[macro_export]
24macro_rules! impl_intern_key { 24macro_rules! impl_intern_key {
@@ -91,12 +91,7 @@ pub const DEFAULT_LRU_CAP: usize = 128;
91pub trait FileLoader { 91pub trait FileLoader {
92 /// Text of the file. 92 /// Text of the file.
93 fn file_text(&self, file_id: FileId) -> Arc<String>; 93 fn file_text(&self, file_id: FileId) -> Arc<String>;
94 /// Note that we intentionally accept a `&str` and not a `&Path` here. This 94 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId>;
95 /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
96 /// so the input is guaranteed to be utf-8 string. One might be tempted to
97 /// introduce some kind of "utf-8 path with / separators", but that's a bad idea. Behold
98 /// `#[path = "C://no/way"]`
99 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
100 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; 95 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
101} 96}
102 97
@@ -155,11 +150,11 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
155 fn file_text(&self, file_id: FileId) -> Arc<String> { 150 fn file_text(&self, file_id: FileId) -> Arc<String> {
156 SourceDatabaseExt::file_text(self.0, file_id) 151 SourceDatabaseExt::file_text(self.0, file_id)
157 } 152 }
158 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 153 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
159 // FIXME: this *somehow* should be platform agnostic... 154 // FIXME: this *somehow* should be platform agnostic...
160 let source_root = self.0.file_source_root(anchor); 155 let source_root = self.0.file_source_root(path.anchor);
161 let source_root = self.0.source_root(source_root); 156 let source_root = self.0.source_root(source_root);
162 source_root.file_set.resolve_path(anchor, path) 157 source_root.file_set.resolve_path(path)
163 } 158 }
164 159
165 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 160 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs
index c0c789cae..b4ccd4488 100644
--- a/crates/hir_def/src/nameres/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/mod_resolution.rs
@@ -1,5 +1,5 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use base_db::FileId; 2use base_db::{AnchoredPath, FileId};
3use hir_expand::name::Name; 3use hir_expand::name::Name;
4use syntax::SmolStr; 4use syntax::SmolStr;
5use test_utils::mark; 5use test_utils::mark;
@@ -77,7 +77,8 @@ impl ModDir {
77 }; 77 };
78 78
79 for candidate in candidate_files.iter() { 79 for candidate in candidate_files.iter() {
80 if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) { 80 let path = AnchoredPath { anchor: file_id, path: candidate.as_str() };
81 if let Some(file_id) = db.resolve_path(path) {
81 let is_mod_rs = candidate.ends_with("mod.rs"); 82 let is_mod_rs = candidate.ends_with("mod.rs");
82 83
83 let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { 84 let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index f8b150850..574c0201a 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -5,8 +5,8 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use base_db::SourceDatabase;
9use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; 8use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
9use base_db::{AnchoredPath, SourceDatabase};
10use hir_expand::db::AstDatabase; 10use hir_expand::db::AstDatabase;
11use hir_expand::diagnostics::Diagnostic; 11use hir_expand::diagnostics::Diagnostic;
12use hir_expand::diagnostics::DiagnosticSinkBuilder; 12use hir_expand::diagnostics::DiagnosticSinkBuilder;
@@ -63,8 +63,8 @@ impl FileLoader for TestDB {
63 fn file_text(&self, file_id: FileId) -> Arc<String> { 63 fn file_text(&self, file_id: FileId) -> Arc<String> {
64 FileLoaderDelegate(self).file_text(file_id) 64 FileLoaderDelegate(self).file_text(file_id)
65 } 65 }
66 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 66 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
67 FileLoaderDelegate(self).resolve_path(anchor, path) 67 FileLoaderDelegate(self).resolve_path(path)
68 } 68 }
69 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 69 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
70 FileLoaderDelegate(self).relevant_crates(file_id) 70 FileLoaderDelegate(self).relevant_crates(file_id)
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 79b970850..f60666a54 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -4,7 +4,7 @@ use crate::{
4 MacroDefId, MacroDefKind, TextSize, 4 MacroDefId, MacroDefKind, TextSize,
5}; 5};
6 6
7use base_db::FileId; 7use base_db::{AnchoredPath, FileId};
8use either::Either; 8use either::Either;
9use mbe::{parse_to_token_tree, ExpandResult}; 9use mbe::{parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 10use parser::FragmentKind;
@@ -324,7 +324,8 @@ fn relative_file(
324 allow_recursion: bool, 324 allow_recursion: bool,
325) -> Option<FileId> { 325) -> Option<FileId> {
326 let call_site = call_id.as_file().original_file(db); 326 let call_site = call_id.as_file().original_file(db);
327 let res = db.resolve_path(call_site, path)?; 327 let path = AnchoredPath { anchor: call_site, path };
328 let res = db.resolve_path(path)?;
328 // Prevent include itself 329 // Prevent include itself
329 if res == call_site && !allow_recursion { 330 if res == call_site && !allow_recursion {
330 None 331 None
diff --git a/crates/hir_expand/src/test_db.rs b/crates/hir_expand/src/test_db.rs
index fca501e1f..7168a9462 100644
--- a/crates/hir_expand/src/test_db.rs
+++ b/crates/hir_expand/src/test_db.rs
@@ -5,7 +5,7 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; 8use base_db::{salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate};
9use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
10 10
11#[salsa::database( 11#[salsa::database(
@@ -40,8 +40,8 @@ impl FileLoader for TestDB {
40 fn file_text(&self, file_id: FileId) -> Arc<String> { 40 fn file_text(&self, file_id: FileId) -> Arc<String> {
41 FileLoaderDelegate(self).file_text(file_id) 41 FileLoaderDelegate(self).file_text(file_id)
42 } 42 }
43 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 43 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
44 FileLoaderDelegate(self).resolve_path(anchor, path) 44 FileLoaderDelegate(self).resolve_path(path)
45 } 45 }
46 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 46 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
47 FileLoaderDelegate(self).relevant_crates(file_id) 47 FileLoaderDelegate(self).relevant_crates(file_id)
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs
index 22254b765..646e16bbe 100644
--- a/crates/hir_ty/src/test_db.rs
+++ b/crates/hir_ty/src/test_db.rs
@@ -5,7 +5,9 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; 8use base_db::{
9 salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
10};
9use hir_def::{db::DefDatabase, ModuleId}; 11use hir_def::{db::DefDatabase, ModuleId};
10use hir_expand::db::AstDatabase; 12use hir_expand::db::AstDatabase;
11use rustc_hash::{FxHashMap, FxHashSet}; 13use rustc_hash::{FxHashMap, FxHashSet};
@@ -67,8 +69,8 @@ impl FileLoader for TestDB {
67 fn file_text(&self, file_id: FileId) -> Arc<String> { 69 fn file_text(&self, file_id: FileId) -> Arc<String> {
68 FileLoaderDelegate(self).file_text(file_id) 70 FileLoaderDelegate(self).file_text(file_id)
69 } 71 }
70 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 72 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
71 FileLoaderDelegate(self).resolve_path(anchor, path) 73 FileLoaderDelegate(self).resolve_path(path)
72 } 74 }
73 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 75 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
74 FileLoaderDelegate(self).relevant_crates(file_id) 76 FileLoaderDelegate(self).relevant_crates(file_id)
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index c8453edb3..d09f3a0a1 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -610,10 +610,12 @@ fn test_fn() {
610 source_file_edits: [], 610 source_file_edits: [],
611 file_system_edits: [ 611 file_system_edits: [
612 CreateFile { 612 CreateFile {
613 anchor: FileId( 613 dst: AnchoredPathBuf {
614 0, 614 anchor: FileId(
615 ), 615 0,
616 dst: "foo.rs", 616 ),
617 path: "foo.rs",
618 },
617 }, 619 },
618 ], 620 ],
619 is_snippet: false, 621 is_snippet: false,
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 24d08651e..29c7a040b 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -8,7 +8,7 @@ use hir::{
8 }, 8 },
9 HasSource, HirDisplay, Semantics, VariantDef, 9 HasSource, HirDisplay, Semantics, VariantDef,
10}; 10};
11use ide_db::base_db::FileId; 11use ide_db::base_db::{AnchoredPathBuf, FileId};
12use ide_db::{ 12use ide_db::{
13 source_change::{FileSystemEdit, SourceFileEdit}, 13 source_change::{FileSystemEdit, SourceFileEdit},
14 RootDatabase, 14 RootDatabase,
@@ -36,8 +36,10 @@ impl DiagnosticWithFix for UnresolvedModule {
36 Some(Fix::new( 36 Some(Fix::new(
37 "Create module", 37 "Create module",
38 FileSystemEdit::CreateFile { 38 FileSystemEdit::CreateFile {
39 anchor: self.file.original_file(sema.db), 39 dst: AnchoredPathBuf {
40 dst: self.candidate.clone(), 40 anchor: self.file.original_file(sema.db),
41 path: self.candidate.clone(),
42 },
41 } 43 }
42 .into(), 44 .into(),
43 unresolved_module.syntax().text_range(), 45 unresolved_module.syntax().text_range(),
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 64fe8bd65..44081f210 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -6,7 +6,7 @@ use std::{
6}; 6};
7 7
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 8use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{FileRange, SourceDatabaseExt}; 9use ide_db::base_db::{AnchoredPathBuf, FileRange, SourceDatabaseExt};
10use ide_db::{ 10use ide_db::{
11 defs::{Definition, NameClass, NameRefClass}, 11 defs::{Definition, NameClass, NameRefClass},
12 RootDatabase, 12 RootDatabase,
@@ -182,12 +182,13 @@ fn rename_mod(
182 match src.value { 182 match src.value {
183 ModuleSource::SourceFile(..) => { 183 ModuleSource::SourceFile(..) => {
184 // mod is defined in path/to/dir/mod.rs 184 // mod is defined in path/to/dir/mod.rs
185 let dst = if module.is_mod_rs(sema.db) { 185 let path = if module.is_mod_rs(sema.db) {
186 format!("../{}/mod.rs", new_name) 186 format!("../{}/mod.rs", new_name)
187 } else { 187 } else {
188 format!("{}.rs", new_name) 188 format!("{}.rs", new_name)
189 }; 189 };
190 let move_file = FileSystemEdit::MoveFile { src: file_id, anchor: file_id, dst }; 190 let dst = AnchoredPathBuf { anchor: file_id, path };
191 let move_file = FileSystemEdit::MoveFile { src: file_id, dst };
191 file_system_edits.push(move_file); 192 file_system_edits.push(move_file);
192 } 193 }
193 ModuleSource::Module(..) => {} 194 ModuleSource::Module(..) => {}
@@ -771,10 +772,12 @@ mod foo<|>;
771 src: FileId( 772 src: FileId(
772 2, 773 2,
773 ), 774 ),
774 anchor: FileId( 775 dst: AnchoredPathBuf {
775 2, 776 anchor: FileId(
776 ), 777 2,
777 dst: "foo2.rs", 778 ),
779 path: "foo2.rs",
780 },
778 }, 781 },
779 ], 782 ],
780 is_snippet: false, 783 is_snippet: false,
@@ -837,10 +840,12 @@ use crate::foo<|>::FooContent;
837 src: FileId( 840 src: FileId(
838 1, 841 1,
839 ), 842 ),
840 anchor: FileId( 843 dst: AnchoredPathBuf {
841 1, 844 anchor: FileId(
842 ), 845 1,
843 dst: "quux.rs", 846 ),
847 path: "quux.rs",
848 },
844 }, 849 },
845 ], 850 ],
846 is_snippet: false, 851 is_snippet: false,
@@ -884,10 +889,12 @@ mod fo<|>o;
884 src: FileId( 889 src: FileId(
885 1, 890 1,
886 ), 891 ),
887 anchor: FileId( 892 dst: AnchoredPathBuf {
888 1, 893 anchor: FileId(
889 ), 894 1,
890 dst: "../foo2/mod.rs", 895 ),
896 path: "../foo2/mod.rs",
897 },
891 }, 898 },
892 ], 899 ],
893 is_snippet: false, 900 is_snippet: false,
@@ -932,10 +939,12 @@ mod outer { mod fo<|>o; }
932 src: FileId( 939 src: FileId(
933 1, 940 1,
934 ), 941 ),
935 anchor: FileId( 942 dst: AnchoredPathBuf {
936 1, 943 anchor: FileId(
937 ), 944 1,
938 dst: "bar.rs", 945 ),
946 path: "bar.rs",
947 },
939 }, 948 },
940 ], 949 ],
941 is_snippet: false, 950 is_snippet: false,
@@ -1016,10 +1025,12 @@ pub mod foo<|>;
1016 src: FileId( 1025 src: FileId(
1017 2, 1026 2,
1018 ), 1027 ),
1019 anchor: FileId( 1028 dst: AnchoredPathBuf {
1020 2, 1029 anchor: FileId(
1021 ), 1030 2,
1022 dst: "foo2.rs", 1031 ),
1032 path: "foo2.rs",
1033 },
1023 }, 1034 },
1024 ], 1035 ],
1025 is_snippet: false, 1036 is_snippet: false,
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index fceaa089a..118c090d7 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -19,8 +19,8 @@ use std::{fmt, sync::Arc};
19 19
20use base_db::{ 20use base_db::{
21 salsa::{self, Durability}, 21 salsa::{self, Durability},
22 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, 22 AnchoredPath, Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate,
23 Upcast, 23 SourceDatabase, Upcast,
24}; 24};
25use hir::db::{AstDatabase, DefDatabase, HirDatabase}; 25use hir::db::{AstDatabase, DefDatabase, HirDatabase};
26use rustc_hash::FxHashSet; 26use rustc_hash::FxHashSet;
@@ -72,8 +72,8 @@ impl FileLoader for RootDatabase {
72 fn file_text(&self, file_id: FileId) -> Arc<String> { 72 fn file_text(&self, file_id: FileId) -> Arc<String> {
73 FileLoaderDelegate(self).file_text(file_id) 73 FileLoaderDelegate(self).file_text(file_id)
74 } 74 }
75 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 75 fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
76 FileLoaderDelegate(self).resolve_path(anchor, path) 76 FileLoaderDelegate(self).resolve_path(path)
77 } 77 }
78 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 78 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
79 FileLoaderDelegate(self).relevant_crates(file_id) 79 FileLoaderDelegate(self).relevant_crates(file_id)
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs
index f1590ec66..e87d98dad 100644
--- a/crates/ide_db/src/source_change.rs
+++ b/crates/ide_db/src/source_change.rs
@@ -3,7 +3,7 @@
3//! 3//!
4//! It can be viewed as a dual for `AnalysisChange`. 4//! It can be viewed as a dual for `AnalysisChange`.
5 5
6use base_db::FileId; 6use base_db::{AnchoredPathBuf, FileId};
7use text_edit::TextEdit; 7use text_edit::TextEdit;
8 8
9#[derive(Default, Debug, Clone)] 9#[derive(Default, Debug, Clone)]
@@ -44,8 +44,8 @@ impl From<Vec<SourceFileEdit>> for SourceChange {
44 44
45#[derive(Debug, Clone)] 45#[derive(Debug, Clone)]
46pub enum FileSystemEdit { 46pub enum FileSystemEdit {
47 CreateFile { anchor: FileId, dst: String }, 47 CreateFile { dst: AnchoredPathBuf },
48 MoveFile { src: FileId, anchor: FileId, dst: String }, 48 MoveFile { src: FileId, dst: AnchoredPathBuf },
49} 49}
50 50
51impl From<FileSystemEdit> for SourceChange { 51impl From<FileSystemEdit> for SourceChange {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index a27495d0d..71dc56915 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -13,6 +13,7 @@ use lsp_types::{SemanticTokens, Url};
13use parking_lot::{Mutex, RwLock}; 13use parking_lot::{Mutex, RwLock};
14use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16use vfs::AnchoredPathBuf;
16 17
17use crate::{ 18use crate::{
18 config::Config, 19 config::Config,
@@ -268,10 +269,10 @@ impl GlobalStateSnapshot {
268 Some(self.mem_docs.get(&path)?.version) 269 Some(self.mem_docs.get(&path)?.version)
269 } 270 }
270 271
271 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url { 272 pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
272 let mut base = self.vfs.read().0.file_path(file_id); 273 let mut base = self.vfs.read().0.file_path(path.anchor);
273 base.pop(); 274 base.pop();
274 let path = base.join(path).unwrap(); 275 let path = base.join(&path.path).unwrap();
275 let path = path.as_path().unwrap(); 276 let path = path.as_path().unwrap();
276 url_from_abs_path(&path) 277 url_from_abs_path(&path)
277 } 278 }
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 01eabe852..715f8927a 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -628,17 +628,17 @@ pub(crate) fn resource_op(
628 file_system_edit: FileSystemEdit, 628 file_system_edit: FileSystemEdit,
629) -> lsp_types::ResourceOp { 629) -> lsp_types::ResourceOp {
630 match file_system_edit { 630 match file_system_edit {
631 FileSystemEdit::CreateFile { anchor, dst } => { 631 FileSystemEdit::CreateFile { dst } => {
632 let uri = snap.anchored_path(anchor, &dst); 632 let uri = snap.anchored_path(&dst);
633 lsp_types::ResourceOp::Create(lsp_types::CreateFile { 633 lsp_types::ResourceOp::Create(lsp_types::CreateFile {
634 uri, 634 uri,
635 options: None, 635 options: None,
636 annotation: None, 636 annotation: None,
637 }) 637 })
638 } 638 }
639 FileSystemEdit::MoveFile { src, anchor, dst } => { 639 FileSystemEdit::MoveFile { src, dst } => {
640 let old_uri = snap.file_id_to_url(src); 640 let old_uri = snap.file_id_to_url(src);
641 let new_uri = snap.anchored_path(anchor, &dst); 641 let new_uri = snap.anchored_path(&dst);
642 lsp_types::ResourceOp::Rename(lsp_types::RenameFile { 642 lsp_types::ResourceOp::Rename(lsp_types::RenameFile {
643 old_uri, 643 old_uri,
644 new_uri, 644 new_uri,
diff --git a/crates/vfs/src/anchored_path.rs b/crates/vfs/src/anchored_path.rs
new file mode 100644
index 000000000..02720a32e
--- /dev/null
+++ b/crates/vfs/src/anchored_path.rs
@@ -0,0 +1,39 @@
1//! Analysis-level representation of file-system paths.
2//!
3//! The primary goal of this is to losslessly represent paths like
4//!
5//! ```
6//! #[path = "./bar.rs"]
7//! mod foo;
8//! ```
9//!
10//! The first approach one might reach for is to use `PathBuf`. The problem here
11//! is that `PathBuf` depends on host target (windows or linux), but
12//! rust-analyzer should be capable to process `#[path = r"C:\bar.rs"]` on Unix.
13//!
14//! The second try is to use a `String`. This also fails, however. Consider a
15//! hypothetical scenario, where rust-analyzer operates in a
16//! networked/distributed mode. There's one global instance of rust-analyzer,
17//! which processes requests from different machines. Now, the semantics of
18//! `#[path = "/abs/path.rs"]` actually depends on which file-system we are at!
19//! That is, even absolute paths exist relative to a file system!
20//!
21//! A more realistic scenario here is virtual VFS paths we use for testing. More
22//! generally, there can be separate "universes" of VFS paths.
23//!
24//! That's why we use anchored representation -- each path carries an info about
25//! a file this path originates from. We can fetch fs/"universe" information
26//! from the anchor than.
27use crate::FileId;
28
29#[derive(Clone, PartialEq, Eq, Debug)]
30pub struct AnchoredPathBuf {
31 pub anchor: FileId,
32 pub path: String,
33}
34
35#[derive(Clone, Copy, PartialEq, Eq, Debug)]
36pub struct AnchoredPath<'a> {
37 pub anchor: FileId,
38 pub path: &'a str,
39}
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs
index 9093fbd97..49ca593ac 100644
--- a/crates/vfs/src/file_set.rs
+++ b/crates/vfs/src/file_set.rs
@@ -7,7 +7,7 @@ use std::fmt;
7use fst::{IntoStreamer, Streamer}; 7use fst::{IntoStreamer, Streamer};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use crate::{FileId, Vfs, VfsPath}; 10use crate::{AnchoredPath, FileId, Vfs, VfsPath};
11 11
12#[derive(Default, Clone, Eq, PartialEq)] 12#[derive(Default, Clone, Eq, PartialEq)]
13pub struct FileSet { 13pub struct FileSet {
@@ -19,10 +19,10 @@ impl FileSet {
19 pub fn len(&self) -> usize { 19 pub fn len(&self) -> usize {
20 self.files.len() 20 self.files.len()
21 } 21 }
22 pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 22 pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
23 let mut base = self.paths[&anchor].clone(); 23 let mut base = self.paths[&path.anchor].clone();
24 base.pop(); 24 base.pop();
25 let path = base.join(path)?; 25 let path = base.join(path.path)?;
26 self.files.get(&path).copied() 26 self.files.get(&path).copied()
27 } 27 }
28 28
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs
index cdf6f1fd0..a3be579a7 100644
--- a/crates/vfs/src/lib.rs
+++ b/crates/vfs/src/lib.rs
@@ -36,6 +36,7 @@
36//! have a single `FileSet` which unions the two sources. 36//! have a single `FileSet` which unions the two sources.
37mod vfs_path; 37mod vfs_path;
38mod path_interner; 38mod path_interner;
39mod anchored_path;
39pub mod file_set; 40pub mod file_set;
40pub mod loader; 41pub mod loader;
41 42
@@ -43,7 +44,10 @@ use std::{fmt, mem};
43 44
44use crate::path_interner::PathInterner; 45use crate::path_interner::PathInterner;
45 46
46pub use crate::vfs_path::VfsPath; 47pub use crate::{
48 anchored_path::{AnchoredPath, AnchoredPathBuf},
49 vfs_path::VfsPath,
50};
47pub use paths::{AbsPath, AbsPathBuf}; 51pub use paths::{AbsPath, AbsPathBuf};
48 52
49#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] 53#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]