Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/load-cargo/src/lib.rs')
-rw-r--r--crates/load-cargo/src/lib.rs162
1 files changed, 156 insertions, 6 deletions
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index 2b5f515c3a..a1c089520d 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -10,8 +10,8 @@ use hir_expand::proc_macro::{
ProcMacros,
};
use ide_db::{
- base_db::{CrateGraph, Env, SourceRoot},
- prime_caches, Change, FxHashMap, RootDatabase,
+ base_db::{CrateGraph, Env, SourceRoot, SourceRootId},
+ prime_caches, ChangeWithProcMacros, FxHashMap, RootDatabase,
};
use itertools::Itertools;
use proc_macro_api::{MacroDylib, ProcMacroServer};
@@ -231,7 +231,7 @@ impl ProjectFolders {
res.load.push(entry);
if root.is_local {
- local_filesets.push(fsc.len());
+ local_filesets.push(fsc.len() as u64);
}
fsc.add_file_set(file_set_roots)
}
@@ -246,7 +246,7 @@ impl ProjectFolders {
#[derive(Default, Debug)]
pub struct SourceRootConfig {
pub fsc: FileSetConfig,
- pub local_filesets: Vec<usize>,
+ pub local_filesets: Vec<u64>,
}
impl SourceRootConfig {
@@ -256,7 +256,7 @@ impl SourceRootConfig {
.into_iter()
.enumerate()
.map(|(idx, file_set)| {
- let is_local = self.local_filesets.contains(&idx);
+ let is_local = self.local_filesets.contains(&(idx as u64));
if is_local {
SourceRoot::new_local(file_set)
} else {
@@ -265,6 +265,31 @@ impl SourceRootConfig {
})
.collect()
}
+
+ /// Maps local source roots to their parent source roots by bytewise comparing of root paths .
+ /// If a `SourceRoot` doesn't have a parent and is local then it is not contained in this mapping but it can be asserted that it is a root `SourceRoot`.
+ pub fn source_root_parent_map(&self) -> FxHashMap<SourceRootId, SourceRootId> {
+ let roots = self.fsc.roots();
+ let mut map = FxHashMap::<SourceRootId, SourceRootId>::default();
+ roots
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, id))| self.local_filesets.contains(id))
+ .filter_map(|(idx, (root, root_id))| {
+ // We are interested in parents if they are also local source roots.
+ // So instead of a non-local parent we may take a local ancestor as a parent to a node.
+ roots.iter().take(idx).find_map(|(root2, root2_id)| {
+ if self.local_filesets.contains(root2_id) && root.starts_with(root2) {
+ return Some((root_id, root2_id));
+ }
+ None
+ })
+ })
+ .for_each(|(child, parent)| {
+ map.insert(SourceRootId(*child as u32), SourceRootId(*parent as u32));
+ });
+ map
+ }
}
/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
@@ -314,7 +339,7 @@ fn load_crate_graph(
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
let mut db = RootDatabase::new(lru_cap);
- let mut analysis_change = Change::new();
+ let mut analysis_change = ChangeWithProcMacros::new();
db.enable_proc_attr_macros();
@@ -397,6 +422,11 @@ mod tests {
use super::*;
+ use ide_db::base_db::SourceRootId;
+ use vfs::{file_set::FileSetConfigBuilder, VfsPath};
+
+ use crate::SourceRootConfig;
+
#[test]
fn test_loading_rust_analyzer() {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
@@ -413,4 +443,124 @@ mod tests {
// RA has quite a few crates, but the exact count doesn't matter
assert!(n_crates > 20);
}
+
+ #[test]
+ fn unrelated_sources() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
+ let vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+
+ assert_eq!(vc, vec![])
+ }
+
+ #[test]
+ fn unrelated_source_sharing_dirname() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
+ let vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+
+ assert_eq!(vc, vec![])
+ }
+
+ #[test]
+ fn basic_child_parent() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc/def".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
+ let vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+
+ assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0))])
+ }
+
+ #[test]
+ fn basic_child_parent_with_unrelated_parents_sib() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2] };
+ let vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+
+ assert_eq!(vc, vec![(SourceRootId(2), SourceRootId(1))])
+ }
+
+ #[test]
+ fn deep_sources_with_parent_missing() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/ghi".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2] };
+ let vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+
+ assert_eq!(vc, vec![])
+ }
+
+ #[test]
+ fn ancestor_can_be_parent() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/jkl".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2] };
+ let vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+
+ assert_eq!(vc, vec![(SourceRootId(2), SourceRootId(1))])
+ }
+
+ #[test]
+ fn ancestor_can_be_parent_2() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/jkl".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/klm".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 2, 3] };
+ let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+ vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
+
+ assert_eq!(vc, vec![(SourceRootId(2), SourceRootId(1)), (SourceRootId(3), SourceRootId(1))])
+ }
+
+ #[test]
+ fn non_locals_are_skipped() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/ghi/jkl".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/klm".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 3] };
+ let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+ vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
+
+ assert_eq!(vc, vec![(SourceRootId(3), SourceRootId(1)),])
+ }
+
+ #[test]
+ fn child_binds_ancestor_if_parent_nonlocal() {
+ let mut builder = FileSetConfigBuilder::default();
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/abc".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/klm".to_owned())]);
+ builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/klm/jkl".to_owned())]);
+ let fsc = builder.build();
+ let src = SourceRootConfig { fsc, local_filesets: vec![0, 1, 3] };
+ let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
+ vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
+
+ assert_eq!(vc, vec![(SourceRootId(3), SourceRootId(1)),])
+ }
}