From 1f6abb7fbae35dbd036032a6ea2a9e04307f1f55 Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 12 Jun 2021 05:16:22 -0700 Subject: Fix libcore not being included in rust-lang/rust module tree If you are opening libcore from rust-lang/rust as opposed to e.g. goto definition from some other crate which would use the sysroot instance of libcore, a `#![cfg(not(test))]` would previously have made all the code excluded from the module tree, breaking the editor experience. This puts in a slight hack that checks for the crate name "core" and turns off `#[cfg(test)]`. --- crates/project_model/src/workspace.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'crates/project_model') diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index ef0f3c9e4..c2edb3327 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs @@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; use anyhow::{format_err, Context, Result}; use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; use cargo_workspace::DepKind; -use cfg::CfgOptions; +use cfg::{CfgAtom, CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use proc_macro_api::ProcMacroClient; use rustc_hash::{FxHashMap, FxHashSet}; @@ -425,6 +425,20 @@ fn cargo_to_crate_graph( let mut has_private = false; // Next, create crates for each package, target pair for pkg in cargo.packages() { + let mut cfg_options = &cfg_options; + let mut replaced_cfg_options; + if cargo[pkg].name == "core" { + // FIXME: in the specific case of libcore in rust-lang/rust (i.e. it is not coming from + // a sysroot), there's a `#![cfg(not(test))]` at the top of it that makes its contents + // get ignored by r-a. We should implement a more general solution for this + + replaced_cfg_options = cfg_options.clone(); + replaced_cfg_options.apply_diff( + CfgDiff::new(Default::default(), vec![CfgAtom::Flag("test".into())]).unwrap(), + ); + cfg_options = &replaced_cfg_options; + }; + has_private |= cargo[pkg].metadata.rustc_private; let mut lib_tgt = None; for &tgt in cargo[pkg].targets.iter() { -- cgit v1.2.3 From 8b77e2692cd97552b1b8d66eb51cec69695b3a5b Mon Sep 17 00:00:00 2001 From: Jade Date: Sun, 13 Jun 2021 21:41:46 -0700 Subject: Implement a config override for the default #[cfg(test)] in cargo crates Fixes crates which vanish when the 'test' cfg atom is set. Fix #7243. Fix #9203. Fix #7225. --- crates/project_model/src/cargo_workspace.rs | 17 ++++ crates/project_model/src/lib.rs | 2 +- crates/project_model/src/workspace.rs | 124 ++++++++++++++++------------ 3 files changed, 88 insertions(+), 55 deletions(-) (limited to 'crates/project_model') diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index ac079f83e..0935ea967 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs @@ -1,5 +1,6 @@ //! See [`CargoWorkspace`]. +use std::iter; use std::path::PathBuf; use std::{convert::TryInto, ops, process::Command, sync::Arc}; @@ -12,6 +13,7 @@ use rustc_hash::FxHashMap; use serde::Deserialize; use serde_json::from_value; +use crate::CfgOverrides; use crate::{build_data::BuildDataConfig, utf8_stdout}; /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo @@ -76,6 +78,21 @@ pub struct CargoConfig { /// rustc private crate source pub rustc_source: Option, + + /// crates to disable `#[cfg(test)]` on + pub unset_test_crates: Vec, +} + +impl CargoConfig { + pub fn cfg_overrides(&self) -> CfgOverrides { + self.unset_test_crates + .iter() + .cloned() + .zip(iter::repeat_with(|| { + cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap() + })) + .collect() + } } pub type Package = Idx; diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 8c6cf94c2..1d408dff2 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs @@ -41,7 +41,7 @@ pub use crate::{ }, project_json::{ProjectJson, ProjectJsonData}, sysroot::Sysroot, - workspace::{PackageRoot, ProjectWorkspace}, + workspace::{CfgOverrides, PackageRoot, ProjectWorkspace}, }; pub use proc_macro_api::ProcMacroClient; diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index c2edb3327..d8217f714 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs @@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; use anyhow::{format_err, Context, Result}; use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; use cargo_workspace::DepKind; -use cfg::{CfgAtom, CfgDiff, CfgOptions}; +use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use proc_macro_api::ProcMacroClient; use rustc_hash::{FxHashMap, FxHashSet}; @@ -22,6 +22,8 @@ use crate::{ Sysroot, TargetKind, }; +pub type CfgOverrides = FxHashMap; + /// `PackageRoot` describes a package root folder. /// Which may be an external dependency, or a member of /// the current workspace. @@ -46,6 +48,7 @@ pub enum ProjectWorkspace { /// FIXME: make this a per-crate map, as, eg, build.rs might have a /// different target. rustc_cfg: Vec, + cfg_overrides: CfgOverrides, }, /// Project workspace was manually specified using a `rust-project.json` file. Json { project: ProjectJson, sysroot: Option, rustc_cfg: Vec }, @@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Make sure this isn't too verbose. match self { - ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f + ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f .debug_struct("Cargo") .field("root", &cargo.workspace_root().file_name()) .field("n_packages", &cargo.packages().len()) @@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace { &rustc.as_ref().map_or(0, |rc| rc.packages().len()), ) .field("n_rustc_cfg", &rustc_cfg.len()) + .field("n_cfg_overrides", &cfg_overrides.len()) .finish(), ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { let mut debug_struct = f.debug_struct("Json"); @@ -164,7 +168,9 @@ impl ProjectWorkspace { }; let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); - ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } + + let cfg_overrides = config.cfg_overrides(); + ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } } }; @@ -213,43 +219,45 @@ impl ProjectWorkspace { }) })) .collect::>(), - ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo - .packages() - .map(|pkg| { - let is_member = cargo[pkg].is_member; - let pkg_root = cargo[pkg].root().to_path_buf(); - - let mut include = vec![pkg_root.clone()]; - include.extend( - build_data - .and_then(|it| it.get(cargo.workspace_root())) - .and_then(|map| map.get(&cargo[pkg].id)) - .and_then(|it| it.out_dir.clone()), - ); + ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => { + cargo + .packages() + .map(|pkg| { + let is_member = cargo[pkg].is_member; + let pkg_root = cargo[pkg].root().to_path_buf(); + + let mut include = vec![pkg_root.clone()]; + include.extend( + build_data + .and_then(|it| it.get(cargo.workspace_root())) + .and_then(|map| map.get(&cargo[pkg].id)) + .and_then(|it| it.out_dir.clone()), + ); - let mut exclude = vec![pkg_root.join(".git")]; - if is_member { - exclude.push(pkg_root.join("target")); - } else { - exclude.push(pkg_root.join("tests")); - exclude.push(pkg_root.join("examples")); - exclude.push(pkg_root.join("benches")); - } - PackageRoot { is_member, include, exclude } - }) - .chain(sysroot.crates().map(|krate| PackageRoot { - is_member: false, - include: vec![sysroot[krate].root_dir().to_path_buf()], - exclude: Vec::new(), - })) - .chain(rustc.into_iter().flat_map(|rustc| { - rustc.packages().map(move |krate| PackageRoot { + let mut exclude = vec![pkg_root.join(".git")]; + if is_member { + exclude.push(pkg_root.join("target")); + } else { + exclude.push(pkg_root.join("tests")); + exclude.push(pkg_root.join("examples")); + exclude.push(pkg_root.join("benches")); + } + PackageRoot { is_member, include, exclude } + }) + .chain(sysroot.crates().map(|krate| PackageRoot { is_member: false, - include: vec![rustc[krate].root().to_path_buf()], + include: vec![sysroot[krate].root_dir().to_path_buf()], exclude: Vec::new(), - }) - })) - .collect(), + })) + .chain(rustc.into_iter().flat_map(|rustc| { + rustc.packages().map(move |krate| PackageRoot { + is_member: false, + include: vec![rustc[krate].root().to_path_buf()], + exclude: Vec::new(), + }) + })) + .collect() + } ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files .into_iter() .map(|detached_file| PackageRoot { @@ -299,16 +307,22 @@ impl ProjectWorkspace { project, sysroot, ), - ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( - rustc_cfg.clone(), - &proc_macro_loader, - load, - cargo, - build_data.and_then(|it| it.get(cargo.workspace_root())), - sysroot, - rustc, - rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), - ), + ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => { + cargo_to_crate_graph( + rustc_cfg.clone(), + cfg_overrides, + &proc_macro_loader, + load, + cargo, + build_data.and_then(|it| it.get(cargo.workspace_root())), + sysroot, + rustc, + rustc + .as_ref() + .zip(build_data) + .and_then(|(it, map)| map.get(it.workspace_root())), + ) + } ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) } @@ -398,6 +412,7 @@ fn project_json_to_crate_graph( fn cargo_to_crate_graph( rustc_cfg: Vec, + override_cfg: &CfgOverrides, proc_macro_loader: &dyn Fn(&Path) -> Vec, load: &mut dyn FnMut(&AbsPath) -> Option, cargo: &CargoWorkspace, @@ -427,15 +442,16 @@ fn cargo_to_crate_graph( for pkg in cargo.packages() { let mut cfg_options = &cfg_options; let mut replaced_cfg_options; - if cargo[pkg].name == "core" { - // FIXME: in the specific case of libcore in rust-lang/rust (i.e. it is not coming from - // a sysroot), there's a `#![cfg(not(test))]` at the top of it that makes its contents - // get ignored by r-a. We should implement a more general solution for this + if let Some(overrides) = override_cfg.get(&cargo[pkg].name) { + // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen + // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while + // working on rust-lang/rust as that's the only time it appears outside sysroot). + // + // A more ideal solution might be to reanalyze crates based on where the cursor is and + // figure out the set of cfgs that would have to apply to make it active. replaced_cfg_options = cfg_options.clone(); - replaced_cfg_options.apply_diff( - CfgDiff::new(Default::default(), vec![CfgAtom::Flag("test".into())]).unwrap(), - ); + replaced_cfg_options.apply_diff(overrides.clone()); cfg_options = &replaced_cfg_options; }; -- cgit v1.2.3