From fcd615e4b76264b4fff7b5be454787bb6a4252ea Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 5 Feb 2019 23:10:49 +0100 Subject: Extract project model to separate crate --- crates/ra_lsp_server/Cargo.toml | 2 +- crates/ra_lsp_server/src/project_model.rs | 42 +---- .../src/project_model/cargo_workspace.rs | 171 -------------------- crates/ra_lsp_server/src/project_model/sysroot.rs | 137 ---------------- crates/ra_project_model/Cargo.toml | 30 ++++ crates/ra_project_model/src/cargo_workspace.rs | 173 +++++++++++++++++++++ crates/ra_project_model/src/lib.rs | 45 ++++++ crates/ra_project_model/src/sysroot.rs | 138 ++++++++++++++++ crates/ra_syntax/Cargo.toml | 2 +- 9 files changed, 391 insertions(+), 349 deletions(-) delete mode 100644 crates/ra_lsp_server/src/project_model/cargo_workspace.rs delete mode 100644 crates/ra_lsp_server/src/project_model/sysroot.rs create mode 100644 crates/ra_project_model/Cargo.toml create mode 100644 crates/ra_project_model/src/cargo_workspace.rs create mode 100644 crates/ra_project_model/src/lib.rs create mode 100644 crates/ra_project_model/src/sysroot.rs (limited to 'crates') diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index bb92747f2..f46d77893 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -19,7 +19,6 @@ url_serde = "0.2.0" lsp-types = "0.55.0" walkdir = "2.2.7" im = "12.0.0" -cargo_metadata = "0.7.0" rustc-hash = "1.0" parking_lot = "0.7.0" @@ -30,6 +29,7 @@ ra_ide_api = { path = "../ra_ide_api" } ra_arena = { path = "../ra_arena" } gen_lsp_server = { path = "../gen_lsp_server" } ra_vfs = { path = "../ra_vfs" } +ra_project_model = { path = "../ra_project_model" } [dev-dependencies] tempfile = "3" diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index fd5875a0a..6800eb138 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -1,34 +1,13 @@ -mod cargo_workspace; -mod sysroot; +use std::path::PathBuf; -use std::path::{Path, PathBuf}; - -use failure::bail; use thread_worker::{WorkerHandle, Worker}; use crate::Result; -pub use crate::project_model::{ - cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, - sysroot::Sysroot, +pub use ra_project_model::{ + ProjectWorkspace, CargoWorkspace, Package, Target, TargetKind, Sysroot, }; -#[derive(Debug, Clone)] -pub struct ProjectWorkspace { - pub(crate) cargo: CargoWorkspace, - pub(crate) sysroot: Sysroot, -} - -impl ProjectWorkspace { - pub fn discover(path: &Path) -> Result { - let cargo_toml = find_cargo_toml(path)?; - let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; - let sysroot = Sysroot::discover(&cargo_toml)?; - let res = ProjectWorkspace { cargo, sysroot }; - Ok(res) - } -} - pub fn workspace_loader() -> (Worker>, WorkerHandle) { thread_worker::spawn::, _>( "workspace loader", @@ -42,18 +21,3 @@ pub fn workspace_loader() -> (Worker>, WorkerH }, ) } - -fn find_cargo_toml(path: &Path) -> Result { - if path.ends_with("Cargo.toml") { - return Ok(path.to_path_buf()); - } - let mut curr = Some(path); - while let Some(path) = curr { - let candidate = path.join("Cargo.toml"); - if candidate.exists() { - return Ok(candidate); - } - curr = path.parent(); - } - bail!("can't find Cargo.toml at {}", path.display()) -} diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs deleted file mode 100644 index 3b76389d2..000000000 --- a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::path::{Path, PathBuf}; - -use cargo_metadata::{MetadataCommand, CargoOpt}; -use ra_syntax::SmolStr; -use ra_arena::{Arena, RawId, impl_arena_id}; -use rustc_hash::FxHashMap; -use failure::format_err; - -use crate::Result; - -/// `CargoWorksapce` represents the logical structure of, well, a Cargo -/// workspace. It pretty closely mirrors `cargo metadata` output. -/// -/// Note that internally, rust analyzer uses a differnet structure: -/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, -/// while this knows about `Pacakges` & `Targets`: purely cargo-related -/// concepts. -#[derive(Debug, Clone)] -pub struct CargoWorkspace { - packages: Arena, - targets: Arena, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Package(RawId); -impl_arena_id!(Package); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Target(RawId); -impl_arena_id!(Target); - -#[derive(Debug, Clone)] -struct PackageData { - name: SmolStr, - manifest: PathBuf, - targets: Vec, - is_member: bool, - dependencies: Vec, -} - -#[derive(Debug, Clone)] -pub struct PackageDependency { - pub pkg: Package, - pub name: SmolStr, -} - -#[derive(Debug, Clone)] -struct TargetData { - pkg: Package, - name: SmolStr, - root: PathBuf, - kind: TargetKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TargetKind { - Bin, - Lib, - Example, - Test, - Bench, - Other, -} - -impl TargetKind { - fn new(kinds: &[String]) -> TargetKind { - for kind in kinds { - return match kind.as_str() { - "bin" => TargetKind::Bin, - "test" => TargetKind::Test, - "bench" => TargetKind::Bench, - "example" => TargetKind::Example, - _ if kind.contains("lib") => TargetKind::Lib, - _ => continue, - }; - } - TargetKind::Other - } -} - -impl Package { - pub fn name(self, ws: &CargoWorkspace) -> &str { - ws.packages[self].name.as_str() - } - pub fn root(self, ws: &CargoWorkspace) -> &Path { - ws.packages[self].manifest.parent().unwrap() - } - pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { - ws.packages[self].targets.iter().cloned() - } - #[allow(unused)] - pub fn is_member(self, ws: &CargoWorkspace) -> bool { - ws.packages[self].is_member - } - pub fn dependencies<'a>( - self, - ws: &'a CargoWorkspace, - ) -> impl Iterator + 'a { - ws.packages[self].dependencies.iter() - } -} - -impl Target { - pub fn package(self, ws: &CargoWorkspace) -> Package { - ws.targets[self].pkg - } - pub fn name(self, ws: &CargoWorkspace) -> &str { - ws.targets[self].name.as_str() - } - pub fn root(self, ws: &CargoWorkspace) -> &Path { - ws.targets[self].root.as_path() - } - pub fn kind(self, ws: &CargoWorkspace) -> TargetKind { - ws.targets[self].kind - } -} - -impl CargoWorkspace { - pub fn from_cargo_metadata(cargo_toml: &Path) -> Result { - let mut meta = MetadataCommand::new(); - meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures); - if let Some(parent) = cargo_toml.parent() { - meta.current_dir(parent); - } - let meta = meta.exec().map_err(|e| format_err!("cargo metadata failed: {}", e))?; - let mut pkg_by_id = FxHashMap::default(); - let mut packages = Arena::default(); - let mut targets = Arena::default(); - - let ws_members = &meta.workspace_members; - - for meta_pkg in meta.packages { - let is_member = ws_members.contains(&meta_pkg.id); - let pkg = packages.alloc(PackageData { - name: meta_pkg.name.into(), - manifest: meta_pkg.manifest_path.clone(), - targets: Vec::new(), - is_member, - dependencies: Vec::new(), - }); - let pkg_data = &mut packages[pkg]; - pkg_by_id.insert(meta_pkg.id.clone(), pkg); - for meta_tgt in meta_pkg.targets { - let tgt = targets.alloc(TargetData { - pkg, - name: meta_tgt.name.into(), - root: meta_tgt.src_path.clone(), - kind: TargetKind::new(meta_tgt.kind.as_slice()), - }); - pkg_data.targets.push(tgt); - } - } - let resolve = meta.resolve.expect("metadata executed with deps"); - for node in resolve.nodes { - let source = pkg_by_id[&node.id]; - for dep_node in node.deps { - let dep = - PackageDependency { name: dep_node.name.into(), pkg: pkg_by_id[&dep_node.pkg] }; - packages[source].dependencies.push(dep); - } - } - - Ok(CargoWorkspace { packages, targets }) - } - pub fn packages<'a>(&'a self) -> impl Iterator + 'a { - self.packages.iter().map(|(id, _pkg)| id) - } - pub fn target_by_root(&self, root: &Path) -> Option { - self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() - } -} diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs deleted file mode 100644 index 49210ac7a..000000000 --- a/crates/ra_lsp_server/src/project_model/sysroot.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::{ - path::{Path, PathBuf}, - process::Command, -}; - -use ra_syntax::SmolStr; -use ra_arena::{Arena, RawId, impl_arena_id}; - -use crate::Result; - -#[derive(Debug, Clone)] -pub struct Sysroot { - crates: Arena, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SysrootCrate(RawId); -impl_arena_id!(SysrootCrate); - -#[derive(Debug, Clone)] -struct SysrootCrateData { - name: SmolStr, - root: PathBuf, - deps: Vec, -} - -impl Sysroot { - pub(crate) fn std(&self) -> Option { - self.by_name("std") - } - - pub(crate) fn crates<'a>(&'a self) -> impl Iterator + 'a { - self.crates.iter().map(|(id, _data)| id) - } - - pub(super) fn discover(cargo_toml: &Path) -> Result { - let rustc_output = Command::new("rustc") - .current_dir(cargo_toml.parent().unwrap()) - .args(&["--print", "sysroot"]) - .output()?; - if !rustc_output.status.success() { - failure::bail!("failed to locate sysroot") - } - let stdout = String::from_utf8(rustc_output.stdout)?; - let sysroot_path = Path::new(stdout.trim()); - let src = sysroot_path.join("lib/rustlib/src/rust/src"); - if !src.exists() { - failure::bail!( - "can't load standard library from sysroot\n\ - {:?}\n\ - try running `rustup component add rust-src`", - src, - ); - } - - let mut sysroot = Sysroot { crates: Arena::default() }; - for name in SYSROOT_CRATES.trim().lines() { - let root = src.join(format!("lib{}", name)).join("lib.rs"); - if root.exists() { - sysroot.crates.alloc(SysrootCrateData { - name: name.into(), - root, - deps: Vec::new(), - }); - } - } - if let Some(std) = sysroot.std() { - for dep in STD_DEPS.trim().lines() { - if let Some(dep) = sysroot.by_name(dep) { - sysroot.crates[std].deps.push(dep) - } - } - } - Ok(sysroot) - } - - fn by_name(&self, name: &str) -> Option { - self.crates.iter().find(|(_id, data)| data.name == name).map(|(id, _data)| id) - } -} - -impl SysrootCrate { - pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr { - &sysroot.crates[self].name - } - pub(crate) fn root(self, sysroot: &Sysroot) -> &Path { - sysroot.crates[self].root.as_path() - } - pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path { - self.root(sysroot).parent().unwrap() - } - pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator + 'a { - sysroot.crates[self].deps.iter().map(|&it| it) - } -} - -const SYSROOT_CRATES: &str = " -std -core -alloc -collections -libc -panic_unwind -proc_macro -rustc_unicode -std_unicode -test -alloc_jemalloc -alloc_system -compiler_builtins -getopts -panic_unwind -panic_abort -rand -term -unwind -build_helper -rustc_asan -rustc_lsan -rustc_msan -rustc_tsan -syntax"; - -const STD_DEPS: &str = " -alloc -alloc_jemalloc -alloc_system -core -panic_abort -rand -compiler_builtins -unwind -rustc_asan -rustc_lsan -rustc_msan -rustc_tsan -build_helper"; diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml new file mode 100644 index 000000000..5215e5232 --- /dev/null +++ b/crates/ra_project_model/Cargo.toml @@ -0,0 +1,30 @@ +[package] +edition = "2018" +name = "ra_project_model" +version = "0.1.0" +authors = ["Aleksey Kladov "] + +[dependencies] +# itertools = "0.8.0" +# join_to_string = "0.1.3" +# log = "0.4.5" +# relative-path = "0.4.0" +# rayon = "1.0.2" +# fst = "0.3.1" +rustc-hash = "1.0" +# parking_lot = "0.7.0" +# unicase = "2.2.0" + +# TODO get rid of these? +failure = "0.1.4" +failure_derive = "0.1.4" + +smol_str = { version = "0.1.9", features = ["serde"] } +walkdir = "2.2.7" + +cargo_metadata = "0.7.0" + +ra_arena = { path = "../ra_arena" } + +[dev-dependencies] +test_utils = { path = "../test_utils" } diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs new file mode 100644 index 000000000..f3e67d0e5 --- /dev/null +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -0,0 +1,173 @@ +use std::path::{Path, PathBuf}; + +use cargo_metadata::{MetadataCommand, CargoOpt}; +use smol_str::SmolStr; +use ra_arena::{Arena, RawId, impl_arena_id}; +use rustc_hash::FxHashMap; +use failure::format_err; + +use crate::Result; + +/// `CargoWorkspace` represents the logical structure of, well, a Cargo +/// workspace. It pretty closely mirrors `cargo metadata` output. +/// +/// Note that internally, rust analyzer uses a different structure: +/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, +/// while this knows about `Pacakges` & `Targets`: purely cargo-related +/// concepts. +#[derive(Debug, Clone)] +pub struct CargoWorkspace { + packages: Arena, + targets: Arena, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Package(RawId); +impl_arena_id!(Package); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Target(RawId); +impl_arena_id!(Target); + +#[derive(Debug, Clone)] +struct PackageData { + name: SmolStr, + manifest: PathBuf, + targets: Vec, + is_member: bool, + dependencies: Vec, +} + +#[derive(Debug, Clone)] +pub struct PackageDependency { + pub pkg: Package, + pub name: SmolStr, +} + +#[derive(Debug, Clone)] +struct TargetData { + pkg: Package, + name: SmolStr, + root: PathBuf, + kind: TargetKind, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TargetKind { + Bin, + Lib, + Example, + Test, + Bench, + Other, +} + +impl TargetKind { + fn new(kinds: &[String]) -> TargetKind { + for kind in kinds { + return match kind.as_str() { + "bin" => TargetKind::Bin, + "test" => TargetKind::Test, + "bench" => TargetKind::Bench, + "example" => TargetKind::Example, + _ if kind.contains("lib") => TargetKind::Lib, + _ => continue, + }; + } + TargetKind::Other + } +} + +impl Package { + pub fn name(self, ws: &CargoWorkspace) -> &str { + ws.packages[self].name.as_str() + } + pub fn root(self, ws: &CargoWorkspace) -> &Path { + ws.packages[self].manifest.parent().unwrap() + } + pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { + ws.packages[self].targets.iter().cloned() + } + #[allow(unused)] + pub fn is_member(self, ws: &CargoWorkspace) -> bool { + ws.packages[self].is_member + } + pub fn dependencies<'a>( + self, + ws: &'a CargoWorkspace, + ) -> impl Iterator + 'a { + ws.packages[self].dependencies.iter() + } +} + +impl Target { + pub fn package(self, ws: &CargoWorkspace) -> Package { + ws.targets[self].pkg + } + pub fn name(self, ws: &CargoWorkspace) -> &str { + ws.targets[self].name.as_str() + } + pub fn root(self, ws: &CargoWorkspace) -> &Path { + ws.targets[self].root.as_path() + } + pub fn kind(self, ws: &CargoWorkspace) -> TargetKind { + ws.targets[self].kind + } +} + +impl CargoWorkspace { + pub fn from_cargo_metadata(cargo_toml: &Path) -> Result { + let mut meta = MetadataCommand::new(); + meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures); + if let Some(parent) = cargo_toml.parent() { + meta.current_dir(parent); + } + let meta = meta.exec().map_err(|e| format_err!("cargo metadata failed: {}", e))?; + let mut pkg_by_id = FxHashMap::default(); + let mut packages = Arena::default(); + let mut targets = Arena::default(); + + let ws_members = &meta.workspace_members; + + for meta_pkg in meta.packages { + let is_member = ws_members.contains(&meta_pkg.id); + let pkg = packages.alloc(PackageData { + name: meta_pkg.name.into(), + manifest: meta_pkg.manifest_path.clone(), + targets: Vec::new(), + is_member, + dependencies: Vec::new(), + }); + let pkg_data = &mut packages[pkg]; + pkg_by_id.insert(meta_pkg.id.clone(), pkg); + for meta_tgt in meta_pkg.targets { + let tgt = targets.alloc(TargetData { + pkg, + name: meta_tgt.name.into(), + root: meta_tgt.src_path.clone(), + kind: TargetKind::new(meta_tgt.kind.as_slice()), + }); + pkg_data.targets.push(tgt); + } + } + let resolve = meta.resolve.expect("metadata executed with deps"); + for node in resolve.nodes { + let source = pkg_by_id[&node.id]; + for dep_node in node.deps { + let dep = + PackageDependency { name: dep_node.name.into(), pkg: pkg_by_id[&dep_node.pkg] }; + packages[source].dependencies.push(dep); + } + } + + Ok(CargoWorkspace { packages, targets }) + } + + pub fn packages<'a>(&'a self) -> impl Iterator + 'a { + self.packages.iter().map(|(id, _pkg)| id) + } + + pub fn target_by_root(&self, root: &Path) -> Option { + self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() + } +} diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs new file mode 100644 index 000000000..3a7bbace7 --- /dev/null +++ b/crates/ra_project_model/src/lib.rs @@ -0,0 +1,45 @@ +mod cargo_workspace; +mod sysroot; + +use std::path::{Path, PathBuf}; + +use failure::bail; + +pub use crate::{ + cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, + sysroot::Sysroot, +}; + +// TODO use own error enum? +pub type Result = ::std::result::Result; + +#[derive(Debug, Clone)] +pub struct ProjectWorkspace { + pub cargo: CargoWorkspace, + pub sysroot: Sysroot, +} + +impl ProjectWorkspace { + pub fn discover(path: &Path) -> Result { + let cargo_toml = find_cargo_toml(path)?; + let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; + let sysroot = Sysroot::discover(&cargo_toml)?; + let res = ProjectWorkspace { cargo, sysroot }; + Ok(res) + } +} + +fn find_cargo_toml(path: &Path) -> Result { + if path.ends_with("Cargo.toml") { + return Ok(path.to_path_buf()); + } + let mut curr = Some(path); + while let Some(path) = curr { + let candidate = path.join("Cargo.toml"); + if candidate.exists() { + return Ok(candidate); + } + curr = path.parent(); + } + bail!("can't find Cargo.toml at {}", path.display()) +} diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs new file mode 100644 index 000000000..18824dbe5 --- /dev/null +++ b/crates/ra_project_model/src/sysroot.rs @@ -0,0 +1,138 @@ +use std::{ + path::{Path, PathBuf}, + process::Command, +}; + +use smol_str::SmolStr; + +use ra_arena::{Arena, RawId, impl_arena_id}; + +use crate::Result; + +#[derive(Debug, Clone)] +pub struct Sysroot { + crates: Arena, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SysrootCrate(RawId); +impl_arena_id!(SysrootCrate); + +#[derive(Debug, Clone)] +struct SysrootCrateData { + name: SmolStr, + root: PathBuf, + deps: Vec, +} + +impl Sysroot { + pub fn std(&self) -> Option { + self.by_name("std") + } + + pub fn crates<'a>(&'a self) -> impl Iterator + 'a { + self.crates.iter().map(|(id, _data)| id) + } + + pub fn discover(cargo_toml: &Path) -> Result { + let rustc_output = Command::new("rustc") + .current_dir(cargo_toml.parent().unwrap()) + .args(&["--print", "sysroot"]) + .output()?; + if !rustc_output.status.success() { + failure::bail!("failed to locate sysroot") + } + let stdout = String::from_utf8(rustc_output.stdout)?; + let sysroot_path = Path::new(stdout.trim()); + let src = sysroot_path.join("lib/rustlib/src/rust/src"); + if !src.exists() { + failure::bail!( + "can't load standard library from sysroot\n\ + {:?}\n\ + try running `rustup component add rust-src`", + src, + ); + } + + let mut sysroot = Sysroot { crates: Arena::default() }; + for name in SYSROOT_CRATES.trim().lines() { + let root = src.join(format!("lib{}", name)).join("lib.rs"); + if root.exists() { + sysroot.crates.alloc(SysrootCrateData { + name: name.into(), + root, + deps: Vec::new(), + }); + } + } + if let Some(std) = sysroot.std() { + for dep in STD_DEPS.trim().lines() { + if let Some(dep) = sysroot.by_name(dep) { + sysroot.crates[std].deps.push(dep) + } + } + } + Ok(sysroot) + } + + fn by_name(&self, name: &str) -> Option { + self.crates.iter().find(|(_id, data)| data.name == name).map(|(id, _data)| id) + } +} + +impl SysrootCrate { + pub fn name(self, sysroot: &Sysroot) -> &SmolStr { + &sysroot.crates[self].name + } + pub fn root(self, sysroot: &Sysroot) -> &Path { + sysroot.crates[self].root.as_path() + } + pub fn root_dir(self, sysroot: &Sysroot) -> &Path { + self.root(sysroot).parent().unwrap() + } + pub fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator + 'a { + sysroot.crates[self].deps.iter().map(|&it| it) + } +} + +const SYSROOT_CRATES: &str = " +std +core +alloc +collections +libc +panic_unwind +proc_macro +rustc_unicode +std_unicode +test +alloc_jemalloc +alloc_system +compiler_builtins +getopts +panic_unwind +panic_abort +rand +term +unwind +build_helper +rustc_asan +rustc_lsan +rustc_msan +rustc_tsan +syntax"; + +const STD_DEPS: &str = " +alloc +alloc_jemalloc +alloc_system +core +panic_abort +rand +compiler_builtins +unwind +rustc_asan +rustc_lsan +rustc_msan +rustc_tsan +build_helper"; diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 0ec8492aa..7c7a85a75 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml @@ -15,7 +15,7 @@ drop_bomb = "0.1.4" parking_lot = "0.7.0" rowan = "0.3.3" -# ideally, `serde` should be enabled by `ra_lsp_serder`, but we enable it here +# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here # to reduce number of compilations text_unit = { version = "0.1.6", features = ["serde"] } smol_str = { version = "0.1.9", features = ["serde"] } -- cgit v1.2.3 From ddbf43b630fa8159ab2ea5e959393bff44e0c73b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 6 Feb 2019 22:54:33 +0100 Subject: Move crate graph generation to ra_project_model --- 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 ++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 83 deletions(-) (limited to 'crates') diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 614325a0f..405634fe0 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 02f2a37a8..23270d0aa 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 5215e5232..f65aabad7 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 3a7bbace7..30612ac84 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 { -- cgit v1.2.3 From 12c70871cca736afa44379e59f8573c60b0ccd0a Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 9 Feb 2019 10:51:06 +0100 Subject: Remove SmolStr from project model --- crates/ra_project_model/Cargo.toml | 8 -------- crates/ra_project_model/src/cargo_workspace.rs | 7 +++---- crates/ra_project_model/src/lib.rs | 4 ++-- crates/ra_project_model/src/sysroot.rs | 6 ++---- 4 files changed, 7 insertions(+), 18 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index f65aabad7..996dce351 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml @@ -5,21 +5,13 @@ version = "0.1.0" authors = ["Aleksey Kladov "] [dependencies] -# itertools = "0.8.0" -# join_to_string = "0.1.3" log = "0.4.5" -# relative-path = "0.4.0" -# rayon = "1.0.2" -# fst = "0.3.1" rustc-hash = "1.0" -# parking_lot = "0.7.0" -# unicase = "2.2.0" # TODO get rid of these? failure = "0.1.4" failure_derive = "0.1.4" -smol_str = { version = "0.1.9", features = ["serde"] } walkdir = "2.2.7" cargo_metadata = "0.7.0" diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index f3e67d0e5..8adf463a6 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -1,7 +1,6 @@ use std::path::{Path, PathBuf}; use cargo_metadata::{MetadataCommand, CargoOpt}; -use smol_str::SmolStr; use ra_arena::{Arena, RawId, impl_arena_id}; use rustc_hash::FxHashMap; use failure::format_err; @@ -31,7 +30,7 @@ impl_arena_id!(Target); #[derive(Debug, Clone)] struct PackageData { - name: SmolStr, + name: String, manifest: PathBuf, targets: Vec, is_member: bool, @@ -41,13 +40,13 @@ struct PackageData { #[derive(Debug, Clone)] pub struct PackageDependency { pub pkg: Package, - pub name: SmolStr, + pub name: String, } #[derive(Debug, Clone)] struct TargetData { pkg: Package, - name: SmolStr, + name: String, root: PathBuf, kind: TargetKind, } diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 30612ac84..abc79684c 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -47,7 +47,7 @@ impl ProjectWorkspace { 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) { + if let Err(_) = crate_graph.add_dep(from, name.into(), to) { log::error!("cyclic dependency between sysroot crates") } } @@ -101,7 +101,7 @@ impl ProjectWorkspace { 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) { + if let Err(_) = crate_graph.add_dep(from, dep.name.clone().into(), to) { log::error!( "cyclic dependency {} -> {}", pkg.name(&self.cargo), diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index 18824dbe5..8b87aa7bd 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs @@ -3,8 +3,6 @@ use std::{ process::Command, }; -use smol_str::SmolStr; - use ra_arena::{Arena, RawId, impl_arena_id}; use crate::Result; @@ -20,7 +18,7 @@ impl_arena_id!(SysrootCrate); #[derive(Debug, Clone)] struct SysrootCrateData { - name: SmolStr, + name: String, root: PathBuf, deps: Vec, } @@ -81,7 +79,7 @@ impl Sysroot { } impl SysrootCrate { - pub fn name(self, sysroot: &Sysroot) -> &SmolStr { + pub fn name(self, sysroot: &Sysroot) -> &str { &sysroot.crates[self].name } pub fn root(self, sysroot: &Sysroot) -> &Path { -- cgit v1.2.3 From 50fd860471f577e9bb7536e74eb181c055033183 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 9 Feb 2019 11:08:24 +0100 Subject: Remove Vfs from project model --- crates/ra_lsp_server/src/server_world.rs | 6 +++++- crates/ra_project_model/Cargo.toml | 1 - crates/ra_project_model/src/lib.rs | 9 +++------ 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 23270d0aa..f97d240fa 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -58,8 +58,12 @@ impl ServerWorldState { // Create crate graph from all the workspaces let mut crate_graph = CrateGraph::default(); + let mut load = |path: &std::path::Path| { + let vfs_file = vfs.load(path); + vfs_file.map(|f| FileId(f.0.into())) + }; for ws in workspaces.iter() { - crate_graph.extend(ws.to_crate_graph(&mut vfs)); + crate_graph.extend(ws.to_crate_graph(&mut load)); } change.set_crate_graph(crate_graph); diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 996dce351..9cdf2b322 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml @@ -18,7 +18,6 @@ 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 abc79684c..156af9e7a 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -7,7 +7,6 @@ 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}, @@ -32,12 +31,11 @@ impl ProjectWorkspace { Ok(res) } - pub fn to_crate_graph(&self, vfs: &mut Vfs) -> CrateGraph { + pub fn to_crate_graph(&self, load: &mut dyn FnMut(&Path) -> Option) -> 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()); + if let Some(file_id) = load(krate.root(&self.sysroot)) { sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); } } @@ -63,8 +61,7 @@ impl ProjectWorkspace { 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()); + if let Some(file_id) = load(root) { let crate_id = crate_graph.add_crate_root(file_id); if tgt.kind(&self.cargo) == TargetKind::Lib { lib_tgt = Some(crate_id); -- cgit v1.2.3 From e91a46eb0c4a355af25656d77dead55c2e29258e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 9 Feb 2019 11:15:02 +0100 Subject: Clean up a bit --- crates/ra_project_model/Cargo.toml | 2 -- crates/ra_project_model/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 9cdf2b322..90f8b8398 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml @@ -8,9 +8,7 @@ authors = ["Aleksey Kladov "] log = "0.4.5" rustc-hash = "1.0" -# TODO get rid of these? failure = "0.1.4" -failure_derive = "0.1.4" walkdir = "2.2.7" diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 156af9e7a..3b1e07149 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -13,7 +13,7 @@ pub use crate::{ sysroot::Sysroot, }; -// TODO use own error enum? +// TODO use proper error enum pub type Result = ::std::result::Result; #[derive(Debug, Clone)] -- cgit v1.2.3