From ddbf43b630fa8159ab2ea5e959393bff44e0c73b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 6 Feb 2019 22:54:33 +0100 Subject: [PATCH] Move crate graph generation to ra_project_model --- Cargo.lock | 3 + crates/ra_db/src/input.rs | 19 +++++ crates/ra_lsp_server/src/server_world.rs | 85 +---------------------- crates/ra_project_model/Cargo.toml | 4 +- crates/ra_project_model/src/lib.rs | 88 ++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f6a132a5f..3f0334f95d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1052,7 +1052,10 @@ dependencies = [ "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ra_arena 0.1.0", + "ra_db 0.1.0", + "ra_vfs 0.1.0", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 614325a0f6..405634fe00 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -91,6 +91,7 @@ impl CrateGraph { assert!(prev.is_none()); crate_id } + pub fn add_dep( &mut self, from: CrateId, @@ -102,22 +103,40 @@ impl CrateGraph { } Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to)) } + pub fn is_empty(&self) -> bool { self.arena.is_empty() } + pub fn crate_root(&self, crate_id: CrateId) -> FileId { self.arena[&crate_id].file_id } + pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option { let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; Some(crate_id) } + pub fn dependencies<'a>( &'a self, crate_id: CrateId, ) -> impl Iterator + 'a { self.arena[&crate_id].dependencies.iter() } + + /// Extends this crate graph by adding a complete disjoint second crate + /// graph. + pub fn extend(&mut self, other: CrateGraph) { + let start = self.arena.len() as u32; + self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { + let new_id = CrateId(id.0 + start); + for dep in &mut data.dependencies { + dep.crate_id = CrateId(dep.crate_id.0 + start); + } + (new_id, data) + })); + } + fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet) -> bool { if !visited.insert(from) { return false; diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 02f2a37a8c..23270d0aa9 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -9,13 +9,12 @@ use ra_ide_api::{ SourceRootId }; use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; -use rustc_hash::FxHashMap; use relative_path::RelativePathBuf; use parking_lot::RwLock; use failure::format_err; use crate::{ - project_model::{ProjectWorkspace, TargetKind}, + project_model::ProjectWorkspace, Result, }; @@ -57,88 +56,10 @@ impl ServerWorldState { change.add_root(SourceRootId(r.0.into()), is_local); } + // Create crate graph from all the workspaces let mut crate_graph = CrateGraph::default(); for ws in workspaces.iter() { - // First, load std - let mut sysroot_crates = FxHashMap::default(); - for krate in ws.sysroot.crates() { - if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) { - let file_id = FileId(file_id.0.into()); - sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); - } - } - for from in ws.sysroot.crates() { - for to in from.deps(&ws.sysroot) { - let name = to.name(&ws.sysroot); - if let (Some(&from), Some(&to)) = - (sysroot_crates.get(&from), sysroot_crates.get(&to)) - { - if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { - log::error!("cyclic dependency between sysroot crates") - } - } - } - } - - let libstd = ws.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); - - let mut pkg_to_lib_crate = FxHashMap::default(); - let mut pkg_crates = FxHashMap::default(); - // Next, create crates for each package, target pair - for pkg in ws.cargo.packages() { - let mut lib_tgt = None; - for tgt in pkg.targets(&ws.cargo) { - let root = tgt.root(&ws.cargo); - if let Some(file_id) = vfs.load(root) { - let file_id = FileId(file_id.0.into()); - let crate_id = crate_graph.add_crate_root(file_id); - if tgt.kind(&ws.cargo) == TargetKind::Lib { - lib_tgt = Some(crate_id); - pkg_to_lib_crate.insert(pkg, crate_id); - } - pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); - } - } - - // Set deps to the std and to the lib target of the current package - for &from in pkg_crates.get(&pkg).into_iter().flatten() { - if let Some(to) = lib_tgt { - if to != from { - if let Err(_) = - crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to) - { - log::error!( - "cyclic dependency between targets of {}", - pkg.name(&ws.cargo) - ) - } - } - } - if let Some(std) = libstd { - if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { - log::error!("cyclic dependency on std for {}", pkg.name(&ws.cargo)) - } - } - } - } - - // Now add a dep ednge from all targets of upstream to the lib - // target of downstream. - for pkg in ws.cargo.packages() { - for dep in pkg.dependencies(&ws.cargo) { - if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { - for &from in pkg_crates.get(&pkg).into_iter().flatten() { - if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) { - log::error!( - "cyclic dependency {} -> {}", - pkg.name(&ws.cargo), - dep.pkg.name(&ws.cargo) - ) - } - } - } - } - } + crate_graph.extend(ws.to_crate_graph(&mut vfs)); } change.set_crate_graph(crate_graph); diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 5215e52326..f65aabad79 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Aleksey Kladov "] [dependencies] # itertools = "0.8.0" # join_to_string = "0.1.3" -# log = "0.4.5" +log = "0.4.5" # relative-path = "0.4.0" # rayon = "1.0.2" # fst = "0.3.1" @@ -25,6 +25,8 @@ walkdir = "2.2.7" cargo_metadata = "0.7.0" ra_arena = { path = "../ra_arena" } +ra_db = { path = "../ra_db" } +ra_vfs = { path = "../ra_vfs" } [dev-dependencies] test_utils = { path = "../test_utils" } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 3a7bbace75..30612ac845 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -4,6 +4,10 @@ mod sysroot; use std::path::{Path, PathBuf}; use failure::bail; +use rustc_hash::FxHashMap; + +use ra_db::{CrateGraph, FileId}; +use ra_vfs::Vfs; pub use crate::{ cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, @@ -27,6 +31,90 @@ impl ProjectWorkspace { let res = ProjectWorkspace { cargo, sysroot }; Ok(res) } + + pub fn to_crate_graph(&self, vfs: &mut Vfs) -> CrateGraph { + let mut crate_graph = CrateGraph::default(); + let mut sysroot_crates = FxHashMap::default(); + for krate in self.sysroot.crates() { + if let Some(file_id) = vfs.load(krate.root(&self.sysroot)) { + let file_id = FileId(file_id.0.into()); + sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); + } + } + for from in self.sysroot.crates() { + for to in from.deps(&self.sysroot) { + let name = to.name(&self.sysroot); + if let (Some(&from), Some(&to)) = + (sysroot_crates.get(&from), sysroot_crates.get(&to)) + { + if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { + log::error!("cyclic dependency between sysroot crates") + } + } + } + } + + let libstd = self.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); + + let mut pkg_to_lib_crate = FxHashMap::default(); + let mut pkg_crates = FxHashMap::default(); + // Next, create crates for each package, target pair + for pkg in self.cargo.packages() { + let mut lib_tgt = None; + for tgt in pkg.targets(&self.cargo) { + let root = tgt.root(&self.cargo); + if let Some(file_id) = vfs.load(root) { + let file_id = FileId(file_id.0.into()); + let crate_id = crate_graph.add_crate_root(file_id); + if tgt.kind(&self.cargo) == TargetKind::Lib { + lib_tgt = Some(crate_id); + pkg_to_lib_crate.insert(pkg, crate_id); + } + pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); + } + } + + // Set deps to the std and to the lib target of the current package + for &from in pkg_crates.get(&pkg).into_iter().flatten() { + if let Some(to) = lib_tgt { + if to != from { + if let Err(_) = crate_graph.add_dep(from, pkg.name(&self.cargo).into(), to) + { + log::error!( + "cyclic dependency between targets of {}", + pkg.name(&self.cargo) + ) + } + } + } + if let Some(std) = libstd { + if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { + log::error!("cyclic dependency on std for {}", pkg.name(&self.cargo)) + } + } + } + } + + // Now add a dep ednge from all targets of upstream to the lib + // target of downstream. + for pkg in self.cargo.packages() { + for dep in pkg.dependencies(&self.cargo) { + if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { + for &from in pkg_crates.get(&pkg).into_iter().flatten() { + if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) { + log::error!( + "cyclic dependency {} -> {}", + pkg.name(&self.cargo), + dep.pkg.name(&self.cargo) + ) + } + } + } + } + } + + crate_graph + } } fn find_cargo_toml(path: &Path) -> Result {