mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Introduce anchored_path
They allow to represent paths like `#[path = "C:\path.rs"] mod foo;` in a lossless cross-platform & network-transparent way.
This commit is contained in:
parent
5e3891c255
commit
6e24321e45
13 changed files with 79 additions and 65 deletions
|
@ -91,12 +91,7 @@ pub const DEFAULT_LRU_CAP: usize = 128;
|
||||||
pub trait FileLoader {
|
pub trait FileLoader {
|
||||||
/// Text of the file.
|
/// Text of the file.
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<String>;
|
fn file_text(&self, file_id: FileId) -> Arc<String>;
|
||||||
/// Note that we intentionally accept a `&str` and not a `&Path` here. This
|
fn resolve_path(&self, path: AnchoredPath) -> Option<FileId>;
|
||||||
/// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
|
|
||||||
/// so the input is guaranteed to be utf-8 string. One might be tempted to
|
|
||||||
/// introduce some kind of "utf-8 path with / separators", but that's a bad idea. Behold
|
|
||||||
/// `#[path = "C://no/way"]`
|
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
|
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +150,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
||||||
SourceDatabaseExt::file_text(self.0, file_id)
|
SourceDatabaseExt::file_text(self.0, file_id)
|
||||||
}
|
}
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
|
||||||
let path = AnchoredPath { anchor, path };
|
|
||||||
// FIXME: this *somehow* should be platform agnostic...
|
// FIXME: this *somehow* should be platform agnostic...
|
||||||
let source_root = self.0.file_source_root(path.anchor);
|
let source_root = self.0.file_source_root(path.anchor);
|
||||||
let source_root = self.0.source_root(source_root);
|
let source_root = self.0.source_root(source_root);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! This module resolves `mod foo;` declaration to file.
|
//! This module resolves `mod foo;` declaration to file.
|
||||||
use base_db::FileId;
|
use base_db::{AnchoredPath, FileId};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
@ -77,7 +77,8 @@ impl ModDir {
|
||||||
};
|
};
|
||||||
|
|
||||||
for candidate in candidate_files.iter() {
|
for candidate in candidate_files.iter() {
|
||||||
if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) {
|
let path = AnchoredPath { anchor: file_id, path: candidate.as_str() };
|
||||||
|
if let Some(file_id) = db.resolve_path(path) {
|
||||||
let is_mod_rs = candidate.ends_with("mod.rs");
|
let is_mod_rs = candidate.ends_with("mod.rs");
|
||||||
|
|
||||||
let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
|
let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
|
||||||
|
|
|
@ -5,8 +5,8 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use base_db::SourceDatabase;
|
|
||||||
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
|
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
|
||||||
|
use base_db::{AnchoredPath, SourceDatabase};
|
||||||
use hir_expand::db::AstDatabase;
|
use hir_expand::db::AstDatabase;
|
||||||
use hir_expand::diagnostics::Diagnostic;
|
use hir_expand::diagnostics::Diagnostic;
|
||||||
use hir_expand::diagnostics::DiagnosticSinkBuilder;
|
use hir_expand::diagnostics::DiagnosticSinkBuilder;
|
||||||
|
@ -63,8 +63,8 @@ impl FileLoader for TestDB {
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
||||||
FileLoaderDelegate(self).file_text(file_id)
|
FileLoaderDelegate(self).file_text(file_id)
|
||||||
}
|
}
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
MacroDefId, MacroDefKind, TextSize,
|
MacroDefId, MacroDefKind, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use base_db::FileId;
|
use base_db::{AnchoredPath, FileId};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use mbe::{parse_to_token_tree, ExpandResult};
|
use mbe::{parse_to_token_tree, ExpandResult};
|
||||||
use parser::FragmentKind;
|
use parser::FragmentKind;
|
||||||
|
@ -324,7 +324,8 @@ fn relative_file(
|
||||||
allow_recursion: bool,
|
allow_recursion: bool,
|
||||||
) -> Option<FileId> {
|
) -> Option<FileId> {
|
||||||
let call_site = call_id.as_file().original_file(db);
|
let call_site = call_id.as_file().original_file(db);
|
||||||
let res = db.resolve_path(call_site, path)?;
|
let path = AnchoredPath { anchor: call_site, path };
|
||||||
|
let res = db.resolve_path(path)?;
|
||||||
// Prevent include itself
|
// Prevent include itself
|
||||||
if res == call_site && !allow_recursion {
|
if res == call_site && !allow_recursion {
|
||||||
None
|
None
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
|
use base_db::{salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
#[salsa::database(
|
#[salsa::database(
|
||||||
|
@ -40,8 +40,8 @@ impl FileLoader for TestDB {
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
||||||
FileLoaderDelegate(self).file_text(file_id)
|
FileLoaderDelegate(self).file_text(file_id)
|
||||||
}
|
}
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
|
|
|
@ -5,7 +5,9 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
|
use base_db::{
|
||||||
|
salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
|
||||||
|
};
|
||||||
use hir_def::{db::DefDatabase, ModuleId};
|
use hir_def::{db::DefDatabase, ModuleId};
|
||||||
use hir_expand::db::AstDatabase;
|
use hir_expand::db::AstDatabase;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
@ -67,8 +69,8 @@ impl FileLoader for TestDB {
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
||||||
FileLoaderDelegate(self).file_text(file_id)
|
FileLoaderDelegate(self).file_text(file_id)
|
||||||
}
|
}
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
|
|
|
@ -610,10 +610,12 @@ fn test_fn() {
|
||||||
source_file_edits: [],
|
source_file_edits: [],
|
||||||
file_system_edits: [
|
file_system_edits: [
|
||||||
CreateFile {
|
CreateFile {
|
||||||
anchor: FileId(
|
dst: AnchoredPathBuf {
|
||||||
0,
|
anchor: FileId(
|
||||||
),
|
0,
|
||||||
dst: "foo.rs",
|
),
|
||||||
|
path: "foo.rs",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
is_snippet: false,
|
is_snippet: false,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use hir::{
|
||||||
},
|
},
|
||||||
HasSource, HirDisplay, Semantics, VariantDef,
|
HasSource, HirDisplay, Semantics, VariantDef,
|
||||||
};
|
};
|
||||||
use ide_db::base_db::FileId;
|
use ide_db::base_db::{AnchoredPathBuf, FileId};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
source_change::{FileSystemEdit, SourceFileEdit},
|
source_change::{FileSystemEdit, SourceFileEdit},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
|
@ -36,8 +36,10 @@ impl DiagnosticWithFix for UnresolvedModule {
|
||||||
Some(Fix::new(
|
Some(Fix::new(
|
||||||
"Create module",
|
"Create module",
|
||||||
FileSystemEdit::CreateFile {
|
FileSystemEdit::CreateFile {
|
||||||
anchor: self.file.original_file(sema.db),
|
dst: AnchoredPathBuf {
|
||||||
dst: self.candidate.clone(),
|
anchor: self.file.original_file(sema.db),
|
||||||
|
path: self.candidate.clone(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
unresolved_module.syntax().text_range(),
|
unresolved_module.syntax().text_range(),
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use hir::{Module, ModuleDef, ModuleSource, Semantics};
|
use hir::{Module, ModuleDef, ModuleSource, Semantics};
|
||||||
use ide_db::base_db::{FileRange, SourceDatabaseExt};
|
use ide_db::base_db::{AnchoredPathBuf, FileRange, SourceDatabaseExt};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::{Definition, NameClass, NameRefClass},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
|
@ -182,12 +182,13 @@ fn rename_mod(
|
||||||
match src.value {
|
match src.value {
|
||||||
ModuleSource::SourceFile(..) => {
|
ModuleSource::SourceFile(..) => {
|
||||||
// mod is defined in path/to/dir/mod.rs
|
// mod is defined in path/to/dir/mod.rs
|
||||||
let dst = if module.is_mod_rs(sema.db) {
|
let path = if module.is_mod_rs(sema.db) {
|
||||||
format!("../{}/mod.rs", new_name)
|
format!("../{}/mod.rs", new_name)
|
||||||
} else {
|
} else {
|
||||||
format!("{}.rs", new_name)
|
format!("{}.rs", new_name)
|
||||||
};
|
};
|
||||||
let move_file = FileSystemEdit::MoveFile { src: file_id, anchor: file_id, dst };
|
let dst = AnchoredPathBuf { anchor: file_id, path };
|
||||||
|
let move_file = FileSystemEdit::MoveFile { src: file_id, dst };
|
||||||
file_system_edits.push(move_file);
|
file_system_edits.push(move_file);
|
||||||
}
|
}
|
||||||
ModuleSource::Module(..) => {}
|
ModuleSource::Module(..) => {}
|
||||||
|
@ -771,10 +772,12 @@ mod foo<|>;
|
||||||
src: FileId(
|
src: FileId(
|
||||||
2,
|
2,
|
||||||
),
|
),
|
||||||
anchor: FileId(
|
dst: AnchoredPathBuf {
|
||||||
2,
|
anchor: FileId(
|
||||||
),
|
2,
|
||||||
dst: "foo2.rs",
|
),
|
||||||
|
path: "foo2.rs",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
is_snippet: false,
|
is_snippet: false,
|
||||||
|
@ -837,10 +840,12 @@ use crate::foo<|>::FooContent;
|
||||||
src: FileId(
|
src: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
anchor: FileId(
|
dst: AnchoredPathBuf {
|
||||||
1,
|
anchor: FileId(
|
||||||
),
|
1,
|
||||||
dst: "quux.rs",
|
),
|
||||||
|
path: "quux.rs",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
is_snippet: false,
|
is_snippet: false,
|
||||||
|
@ -884,10 +889,12 @@ mod fo<|>o;
|
||||||
src: FileId(
|
src: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
anchor: FileId(
|
dst: AnchoredPathBuf {
|
||||||
1,
|
anchor: FileId(
|
||||||
),
|
1,
|
||||||
dst: "../foo2/mod.rs",
|
),
|
||||||
|
path: "../foo2/mod.rs",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
is_snippet: false,
|
is_snippet: false,
|
||||||
|
@ -932,10 +939,12 @@ mod outer { mod fo<|>o; }
|
||||||
src: FileId(
|
src: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
anchor: FileId(
|
dst: AnchoredPathBuf {
|
||||||
1,
|
anchor: FileId(
|
||||||
),
|
1,
|
||||||
dst: "bar.rs",
|
),
|
||||||
|
path: "bar.rs",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
is_snippet: false,
|
is_snippet: false,
|
||||||
|
@ -1016,10 +1025,12 @@ pub mod foo<|>;
|
||||||
src: FileId(
|
src: FileId(
|
||||||
2,
|
2,
|
||||||
),
|
),
|
||||||
anchor: FileId(
|
dst: AnchoredPathBuf {
|
||||||
2,
|
anchor: FileId(
|
||||||
),
|
2,
|
||||||
dst: "foo2.rs",
|
),
|
||||||
|
path: "foo2.rs",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
is_snippet: false,
|
is_snippet: false,
|
||||||
|
|
|
@ -19,8 +19,8 @@ use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
use base_db::{
|
use base_db::{
|
||||||
salsa::{self, Durability},
|
salsa::{self, Durability},
|
||||||
Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
|
AnchoredPath, Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate,
|
||||||
Upcast,
|
SourceDatabase, Upcast,
|
||||||
};
|
};
|
||||||
use hir::db::{AstDatabase, DefDatabase, HirDatabase};
|
use hir::db::{AstDatabase, DefDatabase, HirDatabase};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
@ -72,8 +72,8 @@ impl FileLoader for RootDatabase {
|
||||||
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
fn file_text(&self, file_id: FileId) -> Arc<String> {
|
||||||
FileLoaderDelegate(self).file_text(file_id)
|
FileLoaderDelegate(self).file_text(file_id)
|
||||||
}
|
}
|
||||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
fn resolve_path(&self, path: AnchoredPath) -> Option<FileId> {
|
||||||
FileLoaderDelegate(self).resolve_path(anchor, path)
|
FileLoaderDelegate(self).resolve_path(path)
|
||||||
}
|
}
|
||||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||||
FileLoaderDelegate(self).relevant_crates(file_id)
|
FileLoaderDelegate(self).relevant_crates(file_id)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//!
|
//!
|
||||||
//! It can be viewed as a dual for `AnalysisChange`.
|
//! It can be viewed as a dual for `AnalysisChange`.
|
||||||
|
|
||||||
use base_db::FileId;
|
use base_db::{AnchoredPathBuf, FileId};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
|
@ -44,8 +44,8 @@ impl From<Vec<SourceFileEdit>> for SourceChange {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum FileSystemEdit {
|
pub enum FileSystemEdit {
|
||||||
CreateFile { anchor: FileId, dst: String },
|
CreateFile { dst: AnchoredPathBuf },
|
||||||
MoveFile { src: FileId, anchor: FileId, dst: String },
|
MoveFile { src: FileId, dst: AnchoredPathBuf },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileSystemEdit> for SourceChange {
|
impl From<FileSystemEdit> for SourceChange {
|
||||||
|
|
|
@ -13,6 +13,7 @@ use lsp_types::{SemanticTokens, Url};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
|
use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use vfs::AnchoredPathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
|
@ -268,10 +269,10 @@ impl GlobalStateSnapshot {
|
||||||
Some(self.mem_docs.get(&path)?.version)
|
Some(self.mem_docs.get(&path)?.version)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url {
|
pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
|
||||||
let mut base = self.vfs.read().0.file_path(file_id);
|
let mut base = self.vfs.read().0.file_path(path.anchor);
|
||||||
base.pop();
|
base.pop();
|
||||||
let path = base.join(path).unwrap();
|
let path = base.join(&path.path).unwrap();
|
||||||
let path = path.as_path().unwrap();
|
let path = path.as_path().unwrap();
|
||||||
url_from_abs_path(&path)
|
url_from_abs_path(&path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -628,17 +628,17 @@ pub(crate) fn resource_op(
|
||||||
file_system_edit: FileSystemEdit,
|
file_system_edit: FileSystemEdit,
|
||||||
) -> lsp_types::ResourceOp {
|
) -> lsp_types::ResourceOp {
|
||||||
match file_system_edit {
|
match file_system_edit {
|
||||||
FileSystemEdit::CreateFile { anchor, dst } => {
|
FileSystemEdit::CreateFile { dst } => {
|
||||||
let uri = snap.anchored_path(anchor, &dst);
|
let uri = snap.anchored_path(&dst);
|
||||||
lsp_types::ResourceOp::Create(lsp_types::CreateFile {
|
lsp_types::ResourceOp::Create(lsp_types::CreateFile {
|
||||||
uri,
|
uri,
|
||||||
options: None,
|
options: None,
|
||||||
annotation: None,
|
annotation: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
FileSystemEdit::MoveFile { src, anchor, dst } => {
|
FileSystemEdit::MoveFile { src, dst } => {
|
||||||
let old_uri = snap.file_id_to_url(src);
|
let old_uri = snap.file_id_to_url(src);
|
||||||
let new_uri = snap.anchored_path(anchor, &dst);
|
let new_uri = snap.anchored_path(&dst);
|
||||||
lsp_types::ResourceOp::Rename(lsp_types::RenameFile {
|
lsp_types::ResourceOp::Rename(lsp_types::RenameFile {
|
||||||
old_uri,
|
old_uri,
|
||||||
new_uri,
|
new_uri,
|
||||||
|
|
Loading…
Reference in a new issue