New VFS
This commit is contained in:
@@ -57,17 +57,16 @@
|
||||
//! fn insert_source_code_here() {}
|
||||
//! "
|
||||
//! ```
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
|
||||
use ra_cfg::CfgOptions;
|
||||
use rustc_hash::FxHashMap;
|
||||
use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER};
|
||||
use vfs::{file_set::FileSet, VfsPath};
|
||||
|
||||
use crate::{
|
||||
input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf,
|
||||
SourceDatabaseExt, SourceRoot, SourceRootId,
|
||||
input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, SourceDatabaseExt,
|
||||
SourceRoot, SourceRootId,
|
||||
};
|
||||
|
||||
pub const WORKSPACE: SourceRootId = SourceRootId(0);
|
||||
@@ -105,10 +104,10 @@ impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
|
||||
|
||||
fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId {
|
||||
let file_id = FileId(0);
|
||||
let rel_path: RelativePathBuf = "/main.rs".into();
|
||||
let mut file_set = vfs::file_set::FileSet::default();
|
||||
file_set.insert(file_id, vfs::VfsPath::new_virtual_path("/main.rs".to_string()));
|
||||
|
||||
let mut source_root = SourceRoot::new_local();
|
||||
source_root.insert_file(rel_path.clone(), file_id);
|
||||
let source_root = SourceRoot::new_local(file_set);
|
||||
|
||||
let fixture = parse_single_fixture(ra_fixture);
|
||||
|
||||
@@ -128,7 +127,6 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId
|
||||
meta.cfg,
|
||||
meta.env,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
crate_graph
|
||||
} else {
|
||||
@@ -140,13 +138,11 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
crate_graph
|
||||
};
|
||||
|
||||
db.set_file_text(file_id, Arc::new(ra_fixture.to_string()));
|
||||
db.set_file_relative_path(file_id, rel_path);
|
||||
db.set_file_source_root(file_id, WORKSPACE);
|
||||
db.set_source_root(WORKSPACE, Arc::new(source_root));
|
||||
db.set_crate_graph(Arc::new(crate_graph));
|
||||
@@ -162,7 +158,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
|
||||
let mut crate_deps = Vec::new();
|
||||
let mut default_crate_root: Option<FileId> = None;
|
||||
|
||||
let mut source_root = SourceRoot::new_local();
|
||||
let mut file_set = FileSet::default();
|
||||
let mut source_root_id = WORKSPACE;
|
||||
let mut source_root_prefix = "/".to_string();
|
||||
let mut file_id = FileId(0);
|
||||
@@ -172,8 +168,8 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
|
||||
for entry in fixture.iter() {
|
||||
let meta = match ParsedMeta::from(&entry.meta) {
|
||||
ParsedMeta::Root { path } => {
|
||||
let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local());
|
||||
db.set_source_root(source_root_id, Arc::new(source_root));
|
||||
let file_set = std::mem::replace(&mut file_set, FileSet::default());
|
||||
db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set)));
|
||||
source_root_id.0 += 1;
|
||||
source_root_prefix = path;
|
||||
continue;
|
||||
@@ -190,7 +186,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
|
||||
meta.cfg,
|
||||
meta.env,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let prev = crates.insert(krate.clone(), crate_id);
|
||||
assert!(prev.is_none());
|
||||
@@ -212,9 +207,9 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
|
||||
};
|
||||
|
||||
db.set_file_text(file_id, Arc::new(text));
|
||||
db.set_file_relative_path(file_id, meta.path.clone().into());
|
||||
db.set_file_source_root(file_id, source_root_id);
|
||||
source_root.insert_file(meta.path.into(), file_id);
|
||||
let path = VfsPath::new_virtual_path(meta.path);
|
||||
file_set.insert(file_id, path.into());
|
||||
|
||||
file_id.0 += 1;
|
||||
}
|
||||
@@ -228,7 +223,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
} else {
|
||||
for (from, to) in crate_deps {
|
||||
@@ -238,7 +232,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
|
||||
}
|
||||
}
|
||||
|
||||
db.set_source_root(source_root_id, Arc::new(source_root));
|
||||
db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set)));
|
||||
db.set_crate_graph(Arc::new(crate_graph));
|
||||
|
||||
file_position
|
||||
|
||||
@@ -6,27 +6,15 @@
|
||||
//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
|
||||
//! actual IO is done and lowered to input.
|
||||
|
||||
use std::{
|
||||
fmt, ops,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{fmt, ops, str::FromStr, sync::Arc};
|
||||
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_syntax::SmolStr;
|
||||
use ra_tt::TokenExpander;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use vfs::file_set::FileSet;
|
||||
|
||||
use crate::{RelativePath, RelativePathBuf};
|
||||
|
||||
/// `FileId` is an integer which uniquely identifies a file. File paths are
|
||||
/// messy and system-dependent, so most of the code should work directly with
|
||||
/// `FileId`, without inspecting the path. The mapping between `FileId` and path
|
||||
/// and `SourceRoot` is constant. A file rename is represented as a pair of
|
||||
/// deletion/creation.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FileId(pub u32);
|
||||
pub use vfs::FileId;
|
||||
|
||||
/// Files are grouped into source roots. A source root is a directory on the
|
||||
/// file systems which is watched for changes. Typically it corresponds to a
|
||||
@@ -45,27 +33,18 @@ pub struct SourceRoot {
|
||||
/// Libraries are considered mostly immutable, this assumption is used to
|
||||
/// optimize salsa's query structure
|
||||
pub is_library: bool,
|
||||
files: FxHashMap<RelativePathBuf, FileId>,
|
||||
pub(crate) file_set: FileSet,
|
||||
}
|
||||
|
||||
impl SourceRoot {
|
||||
pub fn new_local() -> SourceRoot {
|
||||
SourceRoot { is_library: false, files: Default::default() }
|
||||
pub fn new_local(file_set: FileSet) -> SourceRoot {
|
||||
SourceRoot { is_library: false, file_set }
|
||||
}
|
||||
pub fn new_library() -> SourceRoot {
|
||||
SourceRoot { is_library: true, files: Default::default() }
|
||||
pub fn new_library(file_set: FileSet) -> SourceRoot {
|
||||
SourceRoot { is_library: true, file_set }
|
||||
}
|
||||
pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
|
||||
self.files.insert(path, file_id);
|
||||
}
|
||||
pub fn remove_file(&mut self, path: &RelativePath) {
|
||||
self.files.remove(path);
|
||||
}
|
||||
pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ {
|
||||
self.files.values().copied()
|
||||
}
|
||||
pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
|
||||
self.files.get(path).copied()
|
||||
pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
|
||||
self.file_set.iter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +120,6 @@ pub struct CrateData {
|
||||
pub display_name: Option<CrateName>,
|
||||
pub cfg_options: CfgOptions,
|
||||
pub env: Env,
|
||||
pub extern_source: ExternSource,
|
||||
pub dependencies: Vec<Dependency>,
|
||||
pub proc_macro: Vec<ProcMacro>,
|
||||
}
|
||||
@@ -152,22 +130,11 @@ pub enum Edition {
|
||||
Edition2015,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ExternSourceId(pub u32);
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Env {
|
||||
entries: FxHashMap<String, String>,
|
||||
}
|
||||
|
||||
// FIXME: Redesign vfs for solve the following limitation ?
|
||||
// Note: Some env variables (e.g. OUT_DIR) are located outside of the
|
||||
// crate. We store a map to allow remap it to ExternSourceId
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ExternSource {
|
||||
extern_paths: FxHashMap<PathBuf, ExternSourceId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Dependency {
|
||||
pub crate_id: CrateId,
|
||||
@@ -182,7 +149,6 @@ impl CrateGraph {
|
||||
display_name: Option<CrateName>,
|
||||
cfg_options: CfgOptions,
|
||||
env: Env,
|
||||
extern_source: ExternSource,
|
||||
proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>,
|
||||
) -> CrateId {
|
||||
let proc_macro =
|
||||
@@ -194,7 +160,6 @@ impl CrateGraph {
|
||||
display_name,
|
||||
cfg_options,
|
||||
env,
|
||||
extern_source,
|
||||
proc_macro,
|
||||
dependencies: Vec::new(),
|
||||
};
|
||||
@@ -334,20 +299,6 @@ impl Env {
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternSource {
|
||||
pub fn extern_path(&self, path: &Path) -> Option<(ExternSourceId, RelativePathBuf)> {
|
||||
self.extern_paths.iter().find_map(|(root_path, id)| {
|
||||
let rel_path = path.strip_prefix(root_path).ok()?;
|
||||
let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
|
||||
Some((*id, rel_path))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_extern_path(&mut self, root_path: &Path, root: ExternSourceId) {
|
||||
self.extern_paths.insert(root_path.to_path_buf(), root);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParseEditionError {
|
||||
invalid_input: String,
|
||||
@@ -378,7 +329,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@@ -387,7 +337,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate3 = graph.add_crate_root(
|
||||
FileId(3u32),
|
||||
@@ -396,7 +345,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
|
||||
assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
|
||||
@@ -413,7 +361,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@@ -422,7 +369,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
|
||||
assert!(graph.add_dep(crate2, CrateName::new("crate2").unwrap(), crate2).is_err());
|
||||
@@ -438,7 +384,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@@ -447,7 +392,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate3 = graph.add_crate_root(
|
||||
FileId(3u32),
|
||||
@@ -456,7 +400,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
|
||||
assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
|
||||
@@ -472,7 +415,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@@ -481,7 +423,6 @@ mod tests {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
|
||||
|
||||
@@ -12,12 +12,13 @@ use rustc_hash::FxHashSet;
|
||||
pub use crate::{
|
||||
cancellation::Canceled,
|
||||
input::{
|
||||
CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource,
|
||||
ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId,
|
||||
CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId,
|
||||
SourceRoot, SourceRootId,
|
||||
},
|
||||
};
|
||||
pub use relative_path::{RelativePath, RelativePathBuf};
|
||||
pub use salsa;
|
||||
pub use vfs::{file_set::FileSet, AbsPathBuf, VfsPath};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_intern_key {
|
||||
@@ -125,8 +126,6 @@ pub trait SourceDatabaseExt: SourceDatabase {
|
||||
#[salsa::input]
|
||||
fn file_text(&self, file_id: FileId) -> Arc<String>;
|
||||
/// Path to a file, relative to the root of its source root.
|
||||
#[salsa::input]
|
||||
fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
|
||||
/// Source root of the file.
|
||||
#[salsa::input]
|
||||
fn file_source_root(&self, file_id: FileId) -> SourceRootId;
|
||||
@@ -161,24 +160,9 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
|
||||
}
|
||||
fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
|
||||
// FIXME: this *somehow* should be platform agnostic...
|
||||
if std::path::Path::new(path).is_absolute() {
|
||||
let krate = *self.relevant_crates(anchor).iter().next()?;
|
||||
let (extern_source_id, relative_file) =
|
||||
self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?;
|
||||
|
||||
let source_root = self.0.source_root(SourceRootId(extern_source_id.0));
|
||||
source_root.file_by_relative_path(&relative_file)
|
||||
} else {
|
||||
let rel_path = {
|
||||
let mut rel_path = self.0.file_relative_path(anchor);
|
||||
assert!(rel_path.pop());
|
||||
rel_path.push(path);
|
||||
rel_path.normalize()
|
||||
};
|
||||
let source_root = self.0.file_source_root(anchor);
|
||||
let source_root = self.0.source_root(source_root);
|
||||
source_root.file_by_relative_path(&rel_path)
|
||||
}
|
||||
let source_root = self.0.file_source_root(anchor);
|
||||
let source_root = self.0.source_root(source_root);
|
||||
source_root.file_set.resolve_path(anchor, path)
|
||||
}
|
||||
|
||||
fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
|
||||
|
||||
Reference in New Issue
Block a user