aboutsummaryrefslogtreecommitdiff
path: root/crates/project_model/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/project_model/src')
-rw-r--r--crates/project_model/src/cargo_workspace.rs17
-rw-r--r--crates/project_model/src/lib.rs2
-rw-r--r--crates/project_model/src/sysroot.rs11
-rw-r--r--crates/project_model/src/workspace.rs135
4 files changed, 111 insertions, 54 deletions
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 @@
1//! See [`CargoWorkspace`]. 1//! See [`CargoWorkspace`].
2 2
3use std::iter;
3use std::path::PathBuf; 4use std::path::PathBuf;
4use std::{convert::TryInto, ops, process::Command, sync::Arc}; 5use std::{convert::TryInto, ops, process::Command, sync::Arc};
5 6
@@ -12,6 +13,7 @@ use rustc_hash::FxHashMap;
12use serde::Deserialize; 13use serde::Deserialize;
13use serde_json::from_value; 14use serde_json::from_value;
14 15
16use crate::CfgOverrides;
15use crate::{build_data::BuildDataConfig, utf8_stdout}; 17use crate::{build_data::BuildDataConfig, utf8_stdout};
16 18
17/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo 19/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
@@ -76,6 +78,21 @@ pub struct CargoConfig {
76 78
77 /// rustc private crate source 79 /// rustc private crate source
78 pub rustc_source: Option<RustcSource>, 80 pub rustc_source: Option<RustcSource>,
81
82 /// crates to disable `#[cfg(test)]` on
83 pub unset_test_crates: Vec<String>,
84}
85
86impl CargoConfig {
87 pub fn cfg_overrides(&self) -> CfgOverrides {
88 self.unset_test_crates
89 .iter()
90 .cloned()
91 .zip(iter::repeat_with(|| {
92 cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap()
93 }))
94 .collect()
95 }
79} 96}
80 97
81pub type Package = Idx<PackageData>; 98pub type Package = Idx<PackageData>;
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::{
41 }, 41 },
42 project_json::{ProjectJson, ProjectJsonData}, 42 project_json::{ProjectJson, ProjectJsonData},
43 sysroot::Sysroot, 43 sysroot::Sysroot,
44 workspace::{PackageRoot, ProjectWorkspace}, 44 workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
45}; 45};
46 46
47pub use proc_macro_api::ProcMacroClient; 47pub use proc_macro_api::ProcMacroClient;
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index a22f79c15..006263da8 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -68,8 +68,9 @@ impl Sysroot {
68 pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { 68 pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
69 let mut sysroot = Sysroot { crates: Arena::default() }; 69 let mut sysroot = Sysroot { crates: Arena::default() };
70 70
71 for name in SYSROOT_CRATES.trim().lines() { 71 for path in SYSROOT_CRATES.trim().lines() {
72 let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)] 72 let name = path.split('/').last().unwrap();
73 let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)]
73 .iter() 74 .iter()
74 .map(|it| sysroot_src_dir.join(it)) 75 .map(|it| sysroot_src_dir.join(it))
75 .find(|it| it.exists()); 76 .find(|it| it.exists());
@@ -191,9 +192,8 @@ panic_abort
191panic_unwind 192panic_unwind
192proc_macro 193proc_macro
193profiler_builtins 194profiler_builtins
194rtstartup
195std 195std
196stdarch 196stdarch/crates/std_detect
197term 197term
198test 198test
199unwind"; 199unwind";
@@ -204,9 +204,8 @@ core
204panic_abort 204panic_abort
205panic_unwind 205panic_unwind
206profiler_builtins 206profiler_builtins
207rtstartup
208proc_macro 207proc_macro
209stdarch 208std_detect
210term 209term
211test 210test
212unwind"; 211unwind";
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index ef0f3c9e4..e67ba2bd9 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};
7use anyhow::{format_err, Context, Result}; 7use anyhow::{format_err, Context, Result};
8use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; 8use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
9use cargo_workspace::DepKind; 9use cargo_workspace::DepKind;
10use cfg::CfgOptions; 10use cfg::{CfgDiff, CfgOptions};
11use paths::{AbsPath, AbsPathBuf}; 11use paths::{AbsPath, AbsPathBuf};
12use proc_macro_api::ProcMacroClient; 12use proc_macro_api::ProcMacroClient;
13use rustc_hash::{FxHashMap, FxHashSet}; 13use rustc_hash::{FxHashMap, FxHashSet};
@@ -22,6 +22,8 @@ use crate::{
22 Sysroot, TargetKind, 22 Sysroot, TargetKind,
23}; 23};
24 24
25pub type CfgOverrides = FxHashMap<String, CfgDiff>;
26
25/// `PackageRoot` describes a package root folder. 27/// `PackageRoot` describes a package root folder.
26/// Which may be an external dependency, or a member of 28/// Which may be an external dependency, or a member of
27/// the current workspace. 29/// the current workspace.
@@ -46,6 +48,7 @@ pub enum ProjectWorkspace {
46 /// FIXME: make this a per-crate map, as, eg, build.rs might have a 48 /// FIXME: make this a per-crate map, as, eg, build.rs might have a
47 /// different target. 49 /// different target.
48 rustc_cfg: Vec<CfgFlag>, 50 rustc_cfg: Vec<CfgFlag>,
51 cfg_overrides: CfgOverrides,
49 }, 52 },
50 /// Project workspace was manually specified using a `rust-project.json` file. 53 /// Project workspace was manually specified using a `rust-project.json` file.
51 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, 54 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
@@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 // Make sure this isn't too verbose. 71 // Make sure this isn't too verbose.
69 match self { 72 match self {
70 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f 73 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f
71 .debug_struct("Cargo") 74 .debug_struct("Cargo")
72 .field("root", &cargo.workspace_root().file_name()) 75 .field("root", &cargo.workspace_root().file_name())
73 .field("n_packages", &cargo.packages().len()) 76 .field("n_packages", &cargo.packages().len())
@@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace {
77 &rustc.as_ref().map_or(0, |rc| rc.packages().len()), 80 &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
78 ) 81 )
79 .field("n_rustc_cfg", &rustc_cfg.len()) 82 .field("n_rustc_cfg", &rustc_cfg.len())
83 .field("n_cfg_overrides", &cfg_overrides.len())
80 .finish(), 84 .finish(),
81 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { 85 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
82 let mut debug_struct = f.debug_struct("Json"); 86 let mut debug_struct = f.debug_struct("Json");
@@ -164,7 +168,9 @@ impl ProjectWorkspace {
164 }; 168 };
165 169
166 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); 170 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
167 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } 171
172 let cfg_overrides = config.cfg_overrides();
173 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides }
168 } 174 }
169 }; 175 };
170 176
@@ -213,43 +219,45 @@ impl ProjectWorkspace {
213 }) 219 })
214 })) 220 }))
215 .collect::<Vec<_>>(), 221 .collect::<Vec<_>>(),
216 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo 222 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => {
217 .packages() 223 cargo
218 .map(|pkg| { 224 .packages()
219 let is_member = cargo[pkg].is_member; 225 .map(|pkg| {
220 let pkg_root = cargo[pkg].root().to_path_buf(); 226 let is_member = cargo[pkg].is_member;
221 227 let pkg_root = cargo[pkg].root().to_path_buf();
222 let mut include = vec![pkg_root.clone()]; 228
223 include.extend( 229 let mut include = vec![pkg_root.clone()];
224 build_data 230 include.extend(
225 .and_then(|it| it.get(cargo.workspace_root())) 231 build_data
226 .and_then(|map| map.get(&cargo[pkg].id)) 232 .and_then(|it| it.get(cargo.workspace_root()))
227 .and_then(|it| it.out_dir.clone()), 233 .and_then(|map| map.get(&cargo[pkg].id))
228 ); 234 .and_then(|it| it.out_dir.clone()),
235 );
229 236
230 let mut exclude = vec![pkg_root.join(".git")]; 237 let mut exclude = vec![pkg_root.join(".git")];
231 if is_member { 238 if is_member {
232 exclude.push(pkg_root.join("target")); 239 exclude.push(pkg_root.join("target"));
233 } else { 240 } else {
234 exclude.push(pkg_root.join("tests")); 241 exclude.push(pkg_root.join("tests"));
235 exclude.push(pkg_root.join("examples")); 242 exclude.push(pkg_root.join("examples"));
236 exclude.push(pkg_root.join("benches")); 243 exclude.push(pkg_root.join("benches"));
237 } 244 }
238 PackageRoot { is_member, include, exclude } 245 PackageRoot { is_member, include, exclude }
239 }) 246 })
240 .chain(sysroot.crates().map(|krate| PackageRoot { 247 .chain(sysroot.crates().map(|krate| PackageRoot {
241 is_member: false,
242 include: vec![sysroot[krate].root_dir().to_path_buf()],
243 exclude: Vec::new(),
244 }))
245 .chain(rustc.into_iter().flat_map(|rustc| {
246 rustc.packages().map(move |krate| PackageRoot {
247 is_member: false, 248 is_member: false,
248 include: vec![rustc[krate].root().to_path_buf()], 249 include: vec![sysroot[krate].root_dir().to_path_buf()],
249 exclude: Vec::new(), 250 exclude: Vec::new(),
250 }) 251 }))
251 })) 252 .chain(rustc.into_iter().flat_map(|rustc| {
252 .collect(), 253 rustc.packages().map(move |krate| PackageRoot {
254 is_member: false,
255 include: vec![rustc[krate].root().to_path_buf()],
256 exclude: Vec::new(),
257 })
258 }))
259 .collect()
260 }
253 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files 261 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
254 .into_iter() 262 .into_iter()
255 .map(|detached_file| PackageRoot { 263 .map(|detached_file| PackageRoot {
@@ -299,16 +307,22 @@ impl ProjectWorkspace {
299 project, 307 project,
300 sysroot, 308 sysroot,
301 ), 309 ),
302 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( 310 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => {
303 rustc_cfg.clone(), 311 cargo_to_crate_graph(
304 &proc_macro_loader, 312 rustc_cfg.clone(),
305 load, 313 cfg_overrides,
306 cargo, 314 &proc_macro_loader,
307 build_data.and_then(|it| it.get(cargo.workspace_root())), 315 load,
308 sysroot, 316 cargo,
309 rustc, 317 build_data.and_then(|it| it.get(cargo.workspace_root())),
310 rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), 318 sysroot,
311 ), 319 rustc,
320 rustc
321 .as_ref()
322 .zip(build_data)
323 .and_then(|(it, map)| map.get(it.workspace_root())),
324 )
325 }
312 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { 326 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
313 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) 327 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
314 } 328 }
@@ -370,6 +384,7 @@ fn project_json_to_crate_graph(
370 file_id, 384 file_id,
371 krate.edition, 385 krate.edition,
372 krate.display_name.clone(), 386 krate.display_name.clone(),
387 cfg_options.clone(),
373 cfg_options, 388 cfg_options,
374 env, 389 env,
375 proc_macro.unwrap_or_default(), 390 proc_macro.unwrap_or_default(),
@@ -398,6 +413,7 @@ fn project_json_to_crate_graph(
398 413
399fn cargo_to_crate_graph( 414fn cargo_to_crate_graph(
400 rustc_cfg: Vec<CfgFlag>, 415 rustc_cfg: Vec<CfgFlag>,
416 override_cfg: &CfgOverrides,
401 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 417 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
402 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 418 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
403 cargo: &CargoWorkspace, 419 cargo: &CargoWorkspace,
@@ -425,6 +441,21 @@ fn cargo_to_crate_graph(
425 let mut has_private = false; 441 let mut has_private = false;
426 // Next, create crates for each package, target pair 442 // Next, create crates for each package, target pair
427 for pkg in cargo.packages() { 443 for pkg in cargo.packages() {
444 let mut cfg_options = &cfg_options;
445 let mut replaced_cfg_options;
446 if let Some(overrides) = override_cfg.get(&cargo[pkg].name) {
447 // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
448 // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
449 // working on rust-lang/rust as that's the only time it appears outside sysroot).
450 //
451 // A more ideal solution might be to reanalyze crates based on where the cursor is and
452 // figure out the set of cfgs that would have to apply to make it active.
453
454 replaced_cfg_options = cfg_options.clone();
455 replaced_cfg_options.apply_diff(overrides.clone());
456 cfg_options = &replaced_cfg_options;
457 };
458
428 has_private |= cargo[pkg].metadata.rustc_private; 459 has_private |= cargo[pkg].metadata.rustc_private;
429 let mut lib_tgt = None; 460 let mut lib_tgt = None;
430 for &tgt in cargo[pkg].targets.iter() { 461 for &tgt in cargo[pkg].targets.iter() {
@@ -550,6 +581,7 @@ fn detached_files_to_crate_graph(
550 Edition::Edition2018, 581 Edition::Edition2018,
551 display_name, 582 display_name,
552 cfg_options.clone(), 583 cfg_options.clone(),
584 cfg_options.clone(),
553 Env::default(), 585 Env::default(),
554 Vec::new(), 586 Vec::new(),
555 ); 587 );
@@ -689,11 +721,19 @@ fn add_target_crate_root(
689 .unwrap_or_default(); 721 .unwrap_or_default();
690 722
691 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); 723 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
724 let mut potential_cfg_options = cfg_options.clone();
725 potential_cfg_options.extend(
726 pkg.features
727 .iter()
728 .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
729 );
730
692 let crate_id = crate_graph.add_crate_root( 731 let crate_id = crate_graph.add_crate_root(
693 file_id, 732 file_id,
694 edition, 733 edition,
695 Some(display_name), 734 Some(display_name),
696 cfg_options, 735 cfg_options,
736 potential_cfg_options,
697 env, 737 env,
698 proc_macro, 738 proc_macro,
699 ); 739 );
@@ -723,6 +763,7 @@ fn sysroot_to_crate_graph(
723 Edition::Edition2018, 763 Edition::Edition2018,
724 Some(display_name), 764 Some(display_name),
725 cfg_options.clone(), 765 cfg_options.clone(),
766 cfg_options.clone(),
726 env, 767 env,
727 proc_macro, 768 proc_macro,
728 ); 769 );