From 189521a4db6e51e954f118367e07bb1cc6d2f40d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 25 Aug 2020 18:34:00 +0200 Subject: [PATCH] Add sysroot shortcut to rust-project.json --- crates/project_model/src/lib.rs | 65 ++++++++++++++++++------ crates/project_model/src/project_json.rs | 11 ++-- docs/user/manual.adoc | 16 ++++-- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 724c586db8..2d91939ce0 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs @@ -39,11 +39,18 @@ pub enum ProjectWorkspace { impl fmt::Debug for ProjectWorkspace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - ProjectWorkspace::Cargo { cargo, .. } => { - f.debug_struct("Cargo").field("n_packages", &cargo.packages().len()).finish() - } + ProjectWorkspace::Cargo { cargo, sysroot } => f + .debug_struct("Cargo") + .field("n_packages", &cargo.packages().len()) + .field("n_sysroot_crates", &sysroot.crates().len()) + .finish(), ProjectWorkspace::Json { project } => { - f.debug_struct("Json").field("n_crates", &project.n_crates()).finish() + let mut debug_struct = f.debug_struct("Json"); + debug_struct.field("n_crates", &project.n_crates()); + if let Some(sysroot) = &project.sysroot { + debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); + } + debug_struct.finish() } } } @@ -210,6 +217,13 @@ impl ProjectWorkspace { }) .collect::>() .into_iter() + .chain(project.sysroot.as_ref().into_iter().flat_map(|sysroot| { + sysroot.crates().map(move |krate| PackageRoot { + is_member: false, + include: vec![sysroot[krate].root_dir().to_path_buf()], + exclude: Vec::new(), + }) + })) .collect::>(), ProjectWorkspace::Cargo { cargo, sysroot } => cargo .packages() @@ -272,6 +286,11 @@ impl ProjectWorkspace { let mut crate_graph = CrateGraph::default(); match self { ProjectWorkspace::Json { project } => { + let sysroot_dps = project + .sysroot + .as_ref() + .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); + let mut cfg_cache: FxHashMap, Vec> = FxHashMap::default(); let crates: FxHashMap<_, _> = project .crates() @@ -309,25 +328,33 @@ impl ProjectWorkspace { .collect(); for (from, krate) in project.crates() { - for dep in &krate.deps { - let to_crate_id = dep.crate_id; - if let (Some(&from), Some(&to)) = - (crates.get(&from), crates.get(&to_crate_id)) - { - if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) { - log::error!("cyclic dependency {:?} -> {:?}", from, to_crate_id); + if let Some(&from) = crates.get(&from) { + if let Some((public_deps, _proc_macro)) = &sysroot_dps { + for (name, to) in public_deps.iter() { + if let Err(_) = crate_graph.add_dep(from, name.clone(), *to) { + log::error!("cyclic dependency on {} for {:?}", name, from) + } + } + } + + for dep in &krate.deps { + let to_crate_id = dep.crate_id; + if let Some(&to) = crates.get(&to_crate_id) { + if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) { + log::error!("cyclic dependency {:?} -> {:?}", from, to); + } } } } } } ProjectWorkspace::Cargo { cargo, sysroot } => { + let (public_deps, libproc_macro) = + sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); + let mut cfg_options = CfgOptions::default(); cfg_options.extend(get_rustc_cfg_options(target)); - let (public_deps, libproc_macro) = - sysroot_to_crate_graph(&mut crate_graph, sysroot, &cfg_options, load); - let mut pkg_to_lib_crate = FxHashMap::default(); let mut pkg_crates = FxHashMap::default(); @@ -410,7 +437,11 @@ impl ProjectWorkspace { } for (name, krate) in public_deps.iter() { if let Err(_) = crate_graph.add_dep(from, name.clone(), *krate) { - log::error!("cyclic dependency on core for {}", &cargo[pkg].name) + log::error!( + "cyclic dependency on {} for {}", + name, + &cargo[pkg].name + ) } } } @@ -485,9 +516,11 @@ fn utf8_stdout(mut cmd: Command) -> Result { fn sysroot_to_crate_graph( crate_graph: &mut CrateGraph, sysroot: &Sysroot, - cfg_options: &CfgOptions, + target: Option<&str>, load: &mut dyn FnMut(&AbsPath) -> Option, ) -> (Vec<(CrateName, CrateId)>, Option) { + let mut cfg_options = CfgOptions::default(); + cfg_options.extend(get_rustc_cfg_options(target)); let sysroot_crates: FxHashMap<_, _> = sysroot .crates() .filter_map(|krate| { diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index ae14e51268..5a0fe749a5 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs @@ -7,11 +7,12 @@ use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; use serde::{de, Deserialize}; -use crate::cfg_flag::CfgFlag; +use crate::{cfg_flag::CfgFlag, Sysroot}; /// Roots and crates that compose this Rust project. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ProjectJson { + pub(crate) sysroot: Option, crates: Vec, } @@ -34,6 +35,7 @@ pub struct Crate { impl ProjectJson { pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { ProjectJson { + sysroot: data.sysroot_src.map(|it| base.join(it)).map(|it| Sysroot::load(&it)), crates: data .crates .into_iter() @@ -43,11 +45,13 @@ impl ProjectJson { && !crate_data.root_module.starts_with("..") || crate_data.root_module.starts_with(base) }); - let root_module = base.join(crate_data.root_module); + let root_module = base.join(crate_data.root_module).normalize(); let (include, exclude) = match crate_data.source { Some(src) => { let absolutize = |dirs: Vec| { - dirs.into_iter().map(|it| base.join(it)).collect::>() + dirs.into_iter() + .map(|it| base.join(it).normalize()) + .collect::>() }; (absolutize(src.include_dirs), absolutize(src.exclude_dirs)) } @@ -89,6 +93,7 @@ impl ProjectJson { #[derive(Deserialize)] pub struct ProjectJsonData { + sysroot_src: Option, crates: Vec, } diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index bebcee0232..144130b51b 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -273,9 +273,19 @@ However, if you use some other build system, you'll have to describe the structu [source,TypeScript] ---- interface JsonProject { - /// The set of crates comprising the current project. - /// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such). - crates: Crate[]; + /// Path to the directory with *source code* of sysroot crates. + /// + /// It should point to the directory where std, core, and friends can be found: + /// https://github.com/rust-lang/rust/tree/master/library. + /// + /// If provided, rust-analyzer automatically adds dependencies on sysroot + /// crates. Conversely, if you omit this path, you can specify sysroot + /// dependencies yourself and, for example, have several different "sysroots" in + /// one graph of crates. + sysroot_src?: string; + /// The set of crates comprising the current project. + /// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such). + crates: Crate[]; } interface Crate {