From 419b5a1bee3424b646991530f31b617a08c8375c Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 7 Mar 2021 12:59:15 +0000 Subject: Extract the large nested block into a function Also add some more detailed comments Extract into function deleted the previous comments --- crates/project_model/src/workspace.rs | 170 ++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 72 deletions(-) (limited to 'crates/project_model/src/workspace.rs') diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index b969420cf..b2ca7a4d2 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs @@ -376,6 +376,7 @@ fn cargo_to_crate_graph( cfg_options.insert_atom("debug_assertions".into()); let mut pkg_crates = FxHashMap::default(); + // Does any crate signal to rust-analyzer that they need the rustc_private crates? let mut has_private = false; // Next, create crates for each package, target pair for pkg in cargo.packages() { @@ -440,92 +441,117 @@ fn cargo_to_crate_graph( } } - let mut rustc_pkg_crates = FxHashMap::default(); - 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 if let Some(rustc_workspace) = rustc { - // rustc-dev crates start from 'rustc_driver' - // We want to collect all crates which are transitive dependencies of rustc_driver - if let Some(root_pkg) = rustc_workspace - .packages() - .find(|package| rustc_workspace[*package].name == "rustc_driver") - { - let mut queue = VecDeque::new(); - queue.push_back(root_pkg); - while let Some(pkg) = queue.pop_front() { - // Don't duplicate packages - if rustc_pkg_crates.contains_key(&pkg) { - continue; - } - for dep in &rustc_workspace[pkg].dependencies { - queue.push_back(dep.pkg); - } - for &tgt in rustc_workspace[pkg].targets.iter() { - if rustc_workspace[tgt].kind != TargetKind::Lib { - continue; - } - if let Some(file_id) = load(&rustc_workspace[tgt].root) { - let crate_id = add_target_crate_root( - &mut crate_graph, - &rustc_workspace[pkg], - rustc_build_data_map - .and_then(|it| it.get(&rustc_workspace[pkg].id)), - &cfg_options, - proc_macro_loader, - file_id, - ); - pkg_to_lib_crate.insert(pkg, crate_id); - // Add dependencies on the core / std / alloc for rustc - for (name, krate) in public_deps.iter() { - add_dep(&mut crate_graph, crate_id, name.clone(), *krate); - } - rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); - } + handle_rustc_crates( + rustc_workspace, + load, + &mut crate_graph, + rustc_build_data_map, + &cfg_options, + proc_macro_loader, + &mut pkg_to_lib_crate, + &public_deps, + cargo, + &pkg_crates, + ); + } + } + crate_graph +} + +fn handle_rustc_crates( + rustc_workspace: &CargoWorkspace, + load: &mut dyn FnMut(&AbsPath) -> Option, + crate_graph: &mut CrateGraph, + rustc_build_data_map: Option<&FxHashMap>, + cfg_options: &CfgOptions, + proc_macro_loader: &dyn Fn(&Path) -> Vec, + pkg_to_lib_crate: &mut FxHashMap, CrateId>, + public_deps: &[(CrateName, CrateId)], + cargo: &CargoWorkspace, + pkg_crates: &FxHashMap, Vec>, +) { + let mut rustc_pkg_crates = FxHashMap::default(); + // The root package of the rustc-dev component is rustc_driver, so we match that + let root_pkg = + rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver"); + // The rustc workspace might be incomplete (such as if rustc-dev is not installed for the current toolchain) + // and `rustcSource` is set to discover. + if let Some(root_pkg) = root_pkg { + // Iterate through every crate in the dependency subtree of rustc_driver using BFS + let mut queue = VecDeque::new(); + queue.push_back(root_pkg); + while let Some(pkg) = queue.pop_front() { + // Don't duplicate packages if they are dependended on a diamond pattern + // N.B. if this line is ommitted, we try and analyse either 48_000 or 480_000 crates + // neither of which makes + if rustc_pkg_crates.contains_key(&pkg) { + continue; + } + for dep in &rustc_workspace[pkg].dependencies { + queue.push_back(dep.pkg); + } + for &tgt in rustc_workspace[pkg].targets.iter() { + if rustc_workspace[tgt].kind != TargetKind::Lib { + continue; + } + if let Some(file_id) = load(&rustc_workspace[tgt].root) { + let crate_id = add_target_crate_root( + crate_graph, + &rustc_workspace[pkg], + rustc_build_data_map.and_then(|it| it.get(&rustc_workspace[pkg].id)), + &cfg_options, + proc_macro_loader, + file_id, + ); + pkg_to_lib_crate.insert(pkg, crate_id); + // Add dependencies on core / std / alloc for this crate + for (name, krate) in public_deps.iter() { + add_dep(crate_graph, crate_id, name.clone(), *krate); } + rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); } } - // Now add a dep edge from all targets of upstream to the lib - // target of downstream. - for pkg in rustc_pkg_crates.keys().copied() { - for dep in rustc_workspace[pkg].dependencies.iter() { - let name = CrateName::new(&dep.name).unwrap(); - if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { - for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { - add_dep(&mut crate_graph, from, name.clone(), to); - } - } + } + } + // Now add a dep edge from all targets of upstream to the lib + // target of downstream. + for pkg in rustc_pkg_crates.keys().copied() { + for dep in rustc_workspace[pkg].dependencies.iter() { + let name = CrateName::new(&dep.name).unwrap(); + if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { + for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { + add_dep(crate_graph, from, name.clone(), to); } } - - // Add dependencies for all crates which opt in to rustc_private libraries - for dep in rustc_workspace.packages() { - let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); - - if let Some(&to) = pkg_to_lib_crate.get(&dep) { - for pkg in cargo.packages() { - let package = &cargo[pkg]; - if !package.metadata.rustc_private { - continue; - } - for &from in pkg_crates.get(&pkg).into_iter().flatten() { - // Avoid creating duplicate dependencies - if !crate_graph[from].dependencies.iter().any(|d| d.name == name) { - add_dep(&mut crate_graph, from, name.clone(), to); - } else { - eprintln!( - "Skipped {} for {:?}", - &name, &crate_graph[from].display_name - ); - } - } + } + } + // Add a dependency on the rustc_private crates for all targets of each package + // which opts in + for dep in rustc_workspace.packages() { + let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); + + if let Some(&to) = pkg_to_lib_crate.get(&dep) { + for pkg in cargo.packages() { + let package = &cargo[pkg]; + if !package.metadata.rustc_private { + continue; + } + for &from in pkg_crates.get(&pkg).into_iter().flatten() { + // Avoid creating duplicate dependencies + // This avoids the situation where `from` depends on e.g. `arrayvec`, but + // `rust_analyzer` thinks that it should use the one from the `rustcSource` + // instead of the one from `crates.io` + if !crate_graph[from].dependencies.iter().any(|d| d.name == name) { + add_dep(crate_graph, from, name.clone(), to); } } } } } - crate_graph } fn add_target_crate_root( -- cgit v1.2.3