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.rs | 237 |
1 files changed, 233 insertions, 4 deletions
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 29c1251cce..7b651257cd 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -10,7 +10,7 @@ use hir_expand::proc_macro::{ ProcMacros, }; use ide_db::{ - base_db::{CrateGraph, Env, SourceRoot}, + base_db::{CrateGraph, Env, SourceRoot, SourceRootId}, prime_caches, ChangeWithProcMacros, FxHashMap, RootDatabase, }; use itertools::Itertools; @@ -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,36 @@ impl SourceRootConfig { }) .collect() } + + /// Maps local source roots to their parent source roots by bytewise comparing of root paths . + /// If a source root doesn't have a parent then its parent is declared as None. + pub fn source_root_parent_map(&self) -> FxHashMap<SourceRootId, Option<SourceRootId>> { + let roots = self.fsc.roots(); + let mut map = FxHashMap::<SourceRootId, Option<SourceRootId>>::default(); + + 'outer: for (idx, (root, root_id)) in roots.iter().enumerate() { + if !self.local_filesets.contains(root_id) { + continue; + } + + for (_, (root2, root2_id)) in roots.iter().enumerate().take(idx).rev() { + if root2.iter().enumerate().all(|(i, c)| &root[i] == c) { + // 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. + if self.local_filesets.contains(root2_id) { + map.insert( + SourceRootId(root_id.to_owned() as u32), + Some(SourceRootId(root2_id.to_owned() as u32)), + ); + continue 'outer; + } + } + } + map.insert(SourceRootId(idx as u32), None); + } + + map + } } /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` @@ -413,4 +443,203 @@ mod tests { // RA has quite a few crates, but the exact count doesn't matter assert!(n_crates > 20); } + + mod source_root_parent { + use ide_db::base_db::SourceRootId; + use vfs::{file_set::FileSetConfigBuilder, VfsPath}; + + use crate::SourceRootConfig; + + macro_rules! virp { + ($s : literal) => { + VfsPath::new_virtual_path(format!($s)) + }; + } + + #[test] + fn test1() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def")]; + builder.add_file_set(root); + builder.add_file_set(root2); + 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(0), None), (SourceRootId(1), None)]) + } + + #[test] + fn test2() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def/abc")]; + builder.add_file_set(root); + builder.add_file_set(root2); + 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(0), None), (SourceRootId(1), None)]) + } + + #[test] + fn test3() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/abc/def")]; + builder.add_file_set(root); + builder.add_file_set(root2); + 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(0), None), (SourceRootId(1), Some(SourceRootId(0)))]) + } + + #[test] + fn test4() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def")]; + let root3 = vec![virp!("/ROOT/def/abc")]; + builder.add_file_set(root); + builder.add_file_set(root2); + builder.add_file_set(root3); + 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(0), None), + (SourceRootId(1), None), + (SourceRootId(2), Some(SourceRootId(1))) + ] + ) + } + + #[test] + fn test5() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/ghi")]; + let root3 = vec![virp!("/ROOT/def/abc")]; + builder.add_file_set(root); + builder.add_file_set(root2); + builder.add_file_set(root3); + 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(0), None), (SourceRootId(1), None), (SourceRootId(2), None)] + ) + } + + #[test] + fn test6() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def")]; + let root3 = vec![virp!("/ROOT/def/ghi/jkl")]; + builder.add_file_set(root); + builder.add_file_set(root2); + builder.add_file_set(root3); + 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(0), None), + (SourceRootId(1), None), + (SourceRootId(2), Some(SourceRootId(1))) + ] + ) + } + + #[test] + fn test7() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def")]; + let root3 = vec![virp!("/ROOT/def/ghi/jkl")]; + let root4 = vec![virp!("/ROOT/def/ghi/klm")]; + builder.add_file_set(root); + builder.add_file_set(root2); + builder.add_file_set(root3); + builder.add_file_set(root4); + 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(0), None), + (SourceRootId(1), None), + (SourceRootId(2), Some(SourceRootId(1))), + (SourceRootId(3), Some(SourceRootId(1))) + ] + ) + } + + #[test] + fn test8() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def")]; + let root3 = vec![virp!("/ROOT/def/ghi/jkl")]; + let root4 = vec![virp!("/ROOT/def/klm")]; + builder.add_file_set(root); + builder.add_file_set(root2); + builder.add_file_set(root3); + builder.add_file_set(root4); + 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(0), None), + (SourceRootId(1), None), + (SourceRootId(3), Some(SourceRootId(1))), + ] + ) + } + + #[test] + fn test9() { + let mut builder = FileSetConfigBuilder::default(); + let root = vec![virp!("/ROOT/abc")]; + let root2 = vec![virp!("/ROOT/def")]; + let root3 = vec![virp!("/ROOT/def/klm")]; + let root4 = vec![virp!("/ROOT/def/klm/jkl")]; + builder.add_file_set(root); + builder.add_file_set(root2); + builder.add_file_set(root3); + builder.add_file_set(root4); + 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(0), None), + (SourceRootId(1), None), + (SourceRootId(3), Some(SourceRootId(1))), + ] + ) + } + } } |