Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/workspace.rs')
| -rw-r--r-- | crates/project-model/src/workspace.rs | 164 |
1 files changed, 36 insertions, 128 deletions
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 065b25d746..5518b6bc7f 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -2,12 +2,7 @@ //! metadata` or `rust-project.json`) into representation stored in the salsa //! database -- `CrateGraph`. -use std::{ - collections::{hash_map::Entry, VecDeque}, - fmt, fs, - process::Command, - sync::Arc, -}; +use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc}; use anyhow::{format_err, Context, Result}; use base_db::{ @@ -849,12 +844,12 @@ fn cargo_to_crate_graph( None => (SysrootPublicDeps::default(), None), }; - let cfg_options = forced_cfg.clone().unwrap_or_else(|| { + let cfg_options = { let mut cfg_options = CfgOptions::default(); cfg_options.extend(rustc_cfg); cfg_options.insert_atom("debug_assertions".into()); cfg_options - }); + }; // Mapping of a package to its library target let mut pkg_to_lib_crate = FxHashMap::default(); @@ -866,6 +861,32 @@ fn cargo_to_crate_graph( for pkg in cargo.packages() { has_private |= cargo[pkg].metadata.rustc_private; + let cfg_options = forced_cfg.clone().unwrap_or_else(|| { + let mut cfg_options = cfg_options.clone(); + + // Add test cfg for local crates + if cargo[pkg].is_local { + cfg_options.insert_atom("test".into()); + } + + let overrides = match override_cfg { + CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), + CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name), + }; + + if let Some(overrides) = overrides { + // 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. + + cfg_options.apply_diff(overrides.clone()); + }; + cfg_options + }); + let mut lib_tgt = None; for &tgt in cargo[pkg].targets.iter() { if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member { @@ -876,7 +897,7 @@ fn cargo_to_crate_graph( // https://github.com/rust-lang/rust-analyzer/issues/11300 continue; } - let Some(file_id) = load(&cargo[tgt].root) else { continue }; + let Some(file_id) = load(&cargo[tgt].root) else { continue }; let crate_id = add_target_crate_root( crate_graph, @@ -904,19 +925,15 @@ fn cargo_to_crate_graph( pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind)); } - let Some(targets) = pkg_crates.get(&pkg) else { continue }; // Set deps to the core, std and to the lib target of the current package - for &(from, kind) in targets { + for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { // Add sysroot deps first so that a lib target named `core` etc. can overwrite them. public_deps.add_to_crate_graph(crate_graph, from); // Add dep edge of all targets to the package's lib target if let Some((to, name)) = lib_tgt.clone() { - if to != from { - if kind == TargetKind::BuildScript { - // build script can not depend on its library target - continue; - } + if to != from && kind != TargetKind::BuildScript { + // (build script can not depend on its library target) // For root projects with dashes in their name, // cargo metadata does not do any normalization, @@ -928,47 +945,6 @@ fn cargo_to_crate_graph( } } - // We now need to duplicate workspace members that are used as dev-dependencies to prevent - // cycles from forming. - - // Map from crate id to it's dev-dependency clone id - let mut test_dupes = FxHashMap::default(); - let mut work = vec![]; - - // Get all dependencies of the workspace members that are used as dev-dependencies - for pkg in cargo.packages() { - for dep in &cargo[pkg].dependencies { - if dep.kind == DepKind::Dev && cargo[dep.pkg].is_member { - work.push(dep.pkg); - } - } - } - while let Some(pkg) = work.pop() { - let Some(&to) = pkg_to_lib_crate.get(&pkg) else { continue }; - match test_dupes.entry(to) { - Entry::Occupied(_) => continue, - Entry::Vacant(v) => { - for dep in &cargo[pkg].dependencies { - if dep.kind == DepKind::Normal && cargo[dep.pkg].is_member { - work.push(dep.pkg); - } - } - v.insert({ - let duped = crate_graph.duplicate(to); - tracing::info!( - "duplicating workspace crate {:?} as it is being used as a dev-dependency: {to:?} -> {duped:?}", - crate_graph[to].display_name - ); - if let Some(proc_macro) = proc_macros.get(&to).cloned() { - proc_macros.insert(duped, proc_macro); - } - crate_graph[duped].cfg_options.insert_atom("test".into()); - duped - }); - } - } - } - // Now add a dep edge from all targets of upstream to the lib // target of downstream. for pkg in cargo.packages() { @@ -982,71 +958,12 @@ fn cargo_to_crate_graph( if (dep.kind == DepKind::Build) != (kind == TargetKind::BuildScript) { continue; } - add_dep( - crate_graph, - from, - name.clone(), - if dep.kind == DepKind::Dev { - // point to the test enabled duplicate for dev-dependencies - test_dupes.get(&to).copied().unwrap_or(to) - } else { - to - }, - ); - if dep.kind == DepKind::Normal && cargo[dep.pkg].is_member { - // Also apply the dependency as a test enabled dependency to the test duplicate - if let Some(&dupe) = test_dupes.get(&from) { - let to = test_dupes.get(&to).copied().unwrap_or_else(|| { - panic!( - "dependency of a dev dependency did not get duplicated! {:?} {:?}", - crate_graph[to].display_name, crate_graph[from].display_name, - ) - }); - add_dep(crate_graph, dupe, name.clone(), to); - } - } + add_dep(crate_graph, from, name.clone(), to) } } } - for (&pkg, targets) in &pkg_crates { - for &(krate, _) in targets { - if let Some(&dupe) = test_dupes.get(&krate) { - tracing::info!( - "{krate:?} {:?} {dupe:?} {:?}", - crate_graph[krate].cfg_options, - crate_graph[dupe].cfg_options - ); - // if the crate got duped as a dev-dep the dupe already has test set - continue; - } - let cfg_options = &mut crate_graph[krate].cfg_options; - - // Add test cfg for local crates - if cargo[pkg].is_local { - cfg_options.insert_atom("test".into()); - } - - let overrides = match override_cfg { - CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), - CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name), - }; - - if let Some(overrides) = overrides { - // 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. - - cfg_options.apply_diff(overrides.clone()); - }; - } - } - - // FIXME: Handle rustc private crates properly when used as dev-dependencies if has_private { // If the user provided a path to rustc sources, we add all the rustc_private crates // and create dependencies on them for the crates which opt-in to that @@ -1170,9 +1087,7 @@ fn handle_rustc_crates( continue; } for dep in &rustc_workspace[pkg].dependencies { - if dep.kind == DepKind::Normal { - queue.push_back(dep.pkg); - } + queue.push_back(dep.pkg); } let mut cfg_options = cfg_options.clone(); @@ -1482,12 +1397,10 @@ fn handle_hack_cargo_workspace( .collect() } -#[track_caller] fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { add_dep_inner(graph, from, Dependency::new(name, to)) } -#[track_caller] fn add_dep_with_prelude( graph: &mut CrateGraph, from: CrateId, @@ -1498,18 +1411,13 @@ fn add_dep_with_prelude( add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude)) } -#[track_caller] fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) { add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude); } -#[track_caller] fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { if let Err(err) = graph.add_dep(from, dep) { - if cfg!(test) { - panic!("{}", err); - } - tracing::error!("{}", err); + tracing::error!("{}", err) } } |