diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index dd9c80691f3d..0ab64a1e0523 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -62,16 +62,16 @@ pub struct PackageRoot { /// Is a member of the current workspace is_member: bool, } - impl PackageRoot { - pub fn new(path: PathBuf, is_member: bool) -> PackageRoot { - PackageRoot { path, is_member } + pub fn new_member(path: PathBuf) -> PackageRoot { + Self { path, is_member: true } } - - pub fn path(&self) -> &PathBuf { + pub fn new_non_member(path: PathBuf) -> PackageRoot { + Self { path, is_member: false } + } + pub fn path(&self) -> &Path { &self.path } - pub fn is_member(&self) -> bool { self.is_member } @@ -130,70 +130,45 @@ impl ProjectWorkspace { pub fn to_roots(&self) -> Vec { match self { ProjectWorkspace::Json { project } => { - let mut roots = Vec::with_capacity(project.roots.len()); - for root in &project.roots { - roots.push(PackageRoot::new(root.path.clone(), true)); - } - roots - } - ProjectWorkspace::Cargo { cargo, sysroot } => { - let mut roots = Vec::with_capacity(cargo.packages().len() + sysroot.crates().len()); - for pkg in cargo.packages() { - let root = cargo[pkg].root().to_path_buf(); - let member = cargo[pkg].is_member; - roots.push(PackageRoot::new(root, member)); - } - for krate in sysroot.crates() { - roots.push(PackageRoot::new(sysroot[krate].root_dir().to_path_buf(), false)) - } - roots + project.roots.iter().map(|r| PackageRoot::new_member(r.path.clone())).collect() } + ProjectWorkspace::Cargo { cargo, sysroot } => cargo + .packages() + .map(|pkg| PackageRoot { + path: cargo[pkg].root().to_path_buf(), + is_member: cargo[pkg].is_member, + }) + .chain(sysroot.crates().map(|krate| { + PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) + })) + .collect(), } } pub fn out_dirs(&self) -> Vec { match self { ProjectWorkspace::Json { project } => { - let mut out_dirs = Vec::with_capacity(project.crates.len()); - for krate in &project.crates { - if let Some(out_dir) = &krate.out_dir { - out_dirs.push(out_dir.to_path_buf()); - } - } - out_dirs + project.crates.iter().filter_map(|krate| krate.out_dir.as_ref()).cloned().collect() } - ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => { - let mut out_dirs = Vec::with_capacity(cargo.packages().len()); - for pkg in cargo.packages() { - if let Some(out_dir) = &cargo[pkg].out_dir { - out_dirs.push(out_dir.to_path_buf()); - } - } - out_dirs + ProjectWorkspace::Cargo { cargo, sysroot: _ } => { + cargo.packages().filter_map(|pkg| cargo[pkg].out_dir.as_ref()).cloned().collect() } } } pub fn proc_macro_dylib_paths(&self) -> Vec { match self { - ProjectWorkspace::Json { project } => { - let mut proc_macro_dylib_paths = Vec::with_capacity(project.crates.len()); - for krate in &project.crates { - if let Some(out_dir) = &krate.proc_macro_dylib_path { - proc_macro_dylib_paths.push(out_dir.to_path_buf()); - } - } - proc_macro_dylib_paths - } - ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => { - let mut proc_macro_dylib_paths = Vec::with_capacity(cargo.packages().len()); - for pkg in cargo.packages() { - if let Some(dylib_path) = &cargo[pkg].proc_macro_dylib_path { - proc_macro_dylib_paths.push(dylib_path.to_path_buf()); - } - } - proc_macro_dylib_paths - } + ProjectWorkspace::Json { project } => project + .crates + .iter() + .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) + .cloned() + .collect(), + ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo + .packages() + .filter_map(|pkg| cargo[pkg].proc_macro_dylib_path.as_ref()) + .cloned() + .collect(), } } @@ -216,10 +191,12 @@ impl ProjectWorkspace { let mut crate_graph = CrateGraph::default(); match self { ProjectWorkspace::Json { project } => { - let mut crates = FxHashMap::default(); - for (id, krate) in project.crates.iter().enumerate() { - let crate_id = json_project::CrateId(id); - if let Some(file_id) = load(&krate.root_module) { + let crates: FxHashMap<_, _> = project + .crates + .iter() + .enumerate() + .filter_map(|(seq_index, krate)| { + let file_id = load(&krate.root_module)?; let edition = match krate.edition { json_project::Edition::Edition2015 => Edition::Edition2015, json_project::Edition::Edition2018 => Edition::Edition2018, @@ -249,8 +226,8 @@ impl ProjectWorkspace { .clone() .map(|it| proc_macro_client.by_dylib_path(&it)); // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env - crates.insert( - crate_id, + Some(( + json_project::CrateId(seq_index), crate_graph.add_crate_root( file_id, edition, @@ -261,9 +238,9 @@ impl ProjectWorkspace { extern_source, proc_macro.unwrap_or_default(), ), - ); - } - } + )) + }) + .collect(); for (id, krate) in project.crates.iter().enumerate() { for dep in &krate.deps { @@ -287,9 +264,11 @@ impl ProjectWorkspace { } } ProjectWorkspace::Cargo { cargo, sysroot } => { - let mut sysroot_crates = FxHashMap::default(); - for krate in sysroot.crates() { - if let Some(file_id) = load(&sysroot[krate].root) { + let sysroot_crates: FxHashMap<_, _> = sysroot + .crates() + .filter_map(|krate| { + let file_id = load(&sysroot[krate].root)?; + // Crates from sysroot have `cfg(test)` disabled let cfg_options = { let mut opts = default_cfg_options.clone(); @@ -300,22 +279,22 @@ impl ProjectWorkspace { let env = Env::default(); let extern_source = ExternSource::default(); let proc_macro = vec![]; + let crate_name = CrateName::new(&sysroot[krate].name) + .expect("Sysroot crate names should not contain dashes"); let crate_id = crate_graph.add_crate_root( file_id, Edition::Edition2018, - Some( - CrateName::new(&sysroot[krate].name) - .expect("Sysroot crate names should not contain dashes"), - ), + Some(crate_name), cfg_options, env, extern_source, proc_macro, ); - sysroot_crates.insert(krate, crate_id); - } - } + Some((krate, crate_id)) + }) + .collect(); + for from in sysroot.crates() { for &to in sysroot[from].deps.iter() { let name = &sysroot[to].name; diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 2c0bde920bef..69133e4e4218 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -36,8 +36,7 @@ pub(crate) fn load_cargo( extern_dirs.extend(ws.out_dirs()); let mut project_roots = ws.to_roots(); - project_roots - .extend(extern_dirs.iter().map(|path| PackageRoot::new(path.to_path_buf(), false))); + project_roots.extend(extern_dirs.iter().cloned().map(PackageRoot::new_non_member)); let (sender, receiver) = unbounded(); let sender = Box::new(move |t| sender.send(t).unwrap()); @@ -46,7 +45,7 @@ pub(crate) fn load_cargo( .iter() .map(|pkg_root| { RootEntry::new( - pkg_root.path().clone(), + pkg_root.path().to_owned(), RustPackageFilterBuilder::default() .set_member(pkg_root.is_member()) .into_vfs_filter(), @@ -58,12 +57,12 @@ pub(crate) fn load_cargo( ); let source_roots = roots - .iter() - .map(|&vfs_root| { + .into_iter() + .map(|vfs_root| { let source_root_id = vfs_root_to_id(vfs_root); let project_root = project_roots .iter() - .find(|it| it.path() == &vfs.root2path(vfs_root)) + .find(|it| it.path() == vfs.root2path(vfs_root)) .unwrap() .clone(); (source_root_id, project_root) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 95e676e0f45c..8d142919628c 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -23,6 +23,7 @@ use lsp_types::{ use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckTask}; use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; use ra_prof::profile; +use ra_project_model::{PackageRoot, ProjectWorkspace}; use ra_vfs::{VfsFile, VfsTask, Watch}; use relative_path::RelativePathBuf; use rustc_hash::FxHashSet; @@ -131,8 +132,8 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) let registration_options = req::DidChangeWatchedFilesRegistrationOptions { watchers: workspaces .iter() - .flat_map(|ws| ws.to_roots()) - .filter(|root| root.is_member()) + .flat_map(ProjectWorkspace::to_roots) + .filter(PackageRoot::is_member) .map(|root| format!("{}/**/*.rs", root.path().display())) .map(|glob_pattern| req::FileSystemWatcher { glob_pattern, kind: None }) .collect(), diff --git a/crates/rust-analyzer/src/main_loop/subscriptions.rs b/crates/rust-analyzer/src/main_loop/subscriptions.rs index bee6437cf34b..2c76418be09a 100644 --- a/crates/rust-analyzer/src/main_loop/subscriptions.rs +++ b/crates/rust-analyzer/src/main_loop/subscriptions.rs @@ -17,6 +17,6 @@ impl Subscriptions { self.subs.remove(&file_id); } pub(crate) fn subscriptions(&self) -> Vec { - self.subs.iter().cloned().collect() + self.subs.iter().copied().collect() } } diff --git a/crates/rust-analyzer/src/vfs_glob.rs b/crates/rust-analyzer/src/vfs_glob.rs index 91b33f94e868..ff37a70080dc 100644 --- a/crates/rust-analyzer/src/vfs_glob.rs +++ b/crates/rust-analyzer/src/vfs_glob.rs @@ -29,10 +29,14 @@ impl RustPackageFilterBuilder { self.is_member = is_member; self } - pub fn exclude(mut self, glob: Glob) -> RustPackageFilterBuilder { - self.exclude.add(glob); + + pub fn exclude(mut self, globs: impl IntoIterator) -> RustPackageFilterBuilder { + for glob in globs.into_iter() { + self.exclude.add(glob); + } self } + pub fn into_vfs_filter(self) -> Box { let RustPackageFilterBuilder { is_member, mut exclude } = self; for &glob in ALWAYS_IGNORED { @@ -87,7 +91,7 @@ fn test_globs() { let filter = RustPackageFilterBuilder::default() .set_member(true) - .exclude(Glob::new("src/llvm-project/**").unwrap()) + .exclude(std::iter::once(Glob::new("src/llvm-project/**").unwrap())) .into_vfs_filter(); assert!(!filter.include_dir(RelativePath::new("src/llvm-project/clang"))); diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 5674f42ef3f8..365f57d8c71e 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -87,44 +87,35 @@ impl WorldState { ) -> WorldState { let mut change = AnalysisChange::new(); - let mut roots = Vec::new(); - roots.extend(folder_roots.iter().map(|path| { - let mut filter = RustPackageFilterBuilder::default().set_member(true); - for glob in exclude_globs.iter() { - filter = filter.exclude(glob.clone()); - } - RootEntry::new(path.clone(), filter.into_vfs_filter()) - })); - for ws in workspaces.iter() { - roots.extend(ws.to_roots().into_iter().map(|pkg_root| { - let mut filter = - RustPackageFilterBuilder::default().set_member(pkg_root.is_member()); - for glob in exclude_globs.iter() { - filter = filter.exclude(glob.clone()); - } - RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter()) - })); - } - - let mut extern_dirs = FxHashSet::default(); - for ws in workspaces.iter() { - extern_dirs.extend(ws.out_dirs()); - } - - let mut extern_source_roots = FxHashMap::default(); - - roots.extend(extern_dirs.iter().map(|path| { - let mut filter = RustPackageFilterBuilder::default().set_member(false); - for glob in exclude_globs.iter() { - filter = filter.exclude(glob.clone()); - } - RootEntry::new(PathBuf::from(&path), filter.into_vfs_filter()) - })); + let extern_dirs: FxHashSet<_> = + workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); + + let roots: Vec<_> = { + let create_filter = |is_member| { + RustPackageFilterBuilder::default() + .set_member(is_member) + .exclude(exclude_globs.iter().cloned()) + .into_vfs_filter() + }; + folder_roots + .iter() + .map(|path| RootEntry::new(path.clone(), create_filter(true))) + .chain(workspaces.iter().flat_map(ProjectWorkspace::to_roots).map(|pkg_root| { + RootEntry::new(pkg_root.path().to_owned(), create_filter(pkg_root.is_member())) + })) + .chain( + extern_dirs + .iter() + .map(|path| RootEntry::new(path.to_owned(), create_filter(false))), + ) + .collect() + }; let (task_sender, task_receiver) = unbounded(); let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch); + let mut extern_source_roots = FxHashMap::default(); for r in vfs_roots { let vfs_root_path = vfs.root2path(r); let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));