Skip to content

Commit 419b5a1

Browse files
committed
Extract the large nested block into a function
Also add some more detailed comments Extract into function deleted the previous comments
1 parent 9246df6 commit 419b5a1

File tree

1 file changed

+98
-72
lines changed

1 file changed

+98
-72
lines changed

crates/project_model/src/workspace.rs

Lines changed: 98 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ fn cargo_to_crate_graph(
376376
cfg_options.insert_atom("debug_assertions".into());
377377

378378
let mut pkg_crates = FxHashMap::default();
379+
// Does any crate signal to rust-analyzer that they need the rustc_private crates?
379380
let mut has_private = false;
380381
// Next, create crates for each package, target pair
381382
for pkg in cargo.packages() {
@@ -440,92 +441,117 @@ fn cargo_to_crate_graph(
440441
}
441442
}
442443

443-
let mut rustc_pkg_crates = FxHashMap::default();
444-
445444
if has_private {
446445
// If the user provided a path to rustc sources, we add all the rustc_private crates
447446
// and create dependencies on them for the crates which opt-in to that
448447
if let Some(rustc_workspace) = rustc {
449-
// rustc-dev crates start from 'rustc_driver'
450-
// We want to collect all crates which are transitive dependencies of rustc_driver
451-
if let Some(root_pkg) = rustc_workspace
452-
.packages()
453-
.find(|package| rustc_workspace[*package].name == "rustc_driver")
454-
{
455-
let mut queue = VecDeque::new();
456-
queue.push_back(root_pkg);
457-
while let Some(pkg) = queue.pop_front() {
458-
// Don't duplicate packages
459-
if rustc_pkg_crates.contains_key(&pkg) {
460-
continue;
461-
}
462-
for dep in &rustc_workspace[pkg].dependencies {
463-
queue.push_back(dep.pkg);
464-
}
465-
for &tgt in rustc_workspace[pkg].targets.iter() {
466-
if rustc_workspace[tgt].kind != TargetKind::Lib {
467-
continue;
468-
}
469-
if let Some(file_id) = load(&rustc_workspace[tgt].root) {
470-
let crate_id = add_target_crate_root(
471-
&mut crate_graph,
472-
&rustc_workspace[pkg],
473-
rustc_build_data_map
474-
.and_then(|it| it.get(&rustc_workspace[pkg].id)),
475-
&cfg_options,
476-
proc_macro_loader,
477-
file_id,
478-
);
479-
pkg_to_lib_crate.insert(pkg, crate_id);
480-
// Add dependencies on the core / std / alloc for rustc
481-
for (name, krate) in public_deps.iter() {
482-
add_dep(&mut crate_graph, crate_id, name.clone(), *krate);
483-
}
484-
rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
485-
}
448+
handle_rustc_crates(
449+
rustc_workspace,
450+
load,
451+
&mut crate_graph,
452+
rustc_build_data_map,
453+
&cfg_options,
454+
proc_macro_loader,
455+
&mut pkg_to_lib_crate,
456+
&public_deps,
457+
cargo,
458+
&pkg_crates,
459+
);
460+
}
461+
}
462+
crate_graph
463+
}
464+
465+
fn handle_rustc_crates(
466+
rustc_workspace: &CargoWorkspace,
467+
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
468+
crate_graph: &mut CrateGraph,
469+
rustc_build_data_map: Option<&FxHashMap<String, BuildData>>,
470+
cfg_options: &CfgOptions,
471+
proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
472+
pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
473+
public_deps: &[(CrateName, CrateId)],
474+
cargo: &CargoWorkspace,
475+
pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<CrateId>>,
476+
) {
477+
let mut rustc_pkg_crates = FxHashMap::default();
478+
// The root package of the rustc-dev component is rustc_driver, so we match that
479+
let root_pkg =
480+
rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver");
481+
// The rustc workspace might be incomplete (such as if rustc-dev is not installed for the current toolchain)
482+
// and `rustcSource` is set to discover.
483+
if let Some(root_pkg) = root_pkg {
484+
// Iterate through every crate in the dependency subtree of rustc_driver using BFS
485+
let mut queue = VecDeque::new();
486+
queue.push_back(root_pkg);
487+
while let Some(pkg) = queue.pop_front() {
488+
// Don't duplicate packages if they are dependended on a diamond pattern
489+
// N.B. if this line is ommitted, we try and analyse either 48_000 or 480_000 crates
490+
// neither of which makes
491+
if rustc_pkg_crates.contains_key(&pkg) {
492+
continue;
493+
}
494+
for dep in &rustc_workspace[pkg].dependencies {
495+
queue.push_back(dep.pkg);
496+
}
497+
for &tgt in rustc_workspace[pkg].targets.iter() {
498+
if rustc_workspace[tgt].kind != TargetKind::Lib {
499+
continue;
500+
}
501+
if let Some(file_id) = load(&rustc_workspace[tgt].root) {
502+
let crate_id = add_target_crate_root(
503+
crate_graph,
504+
&rustc_workspace[pkg],
505+
rustc_build_data_map.and_then(|it| it.get(&rustc_workspace[pkg].id)),
506+
&cfg_options,
507+
proc_macro_loader,
508+
file_id,
509+
);
510+
pkg_to_lib_crate.insert(pkg, crate_id);
511+
// Add dependencies on core / std / alloc for this crate
512+
for (name, krate) in public_deps.iter() {
513+
add_dep(crate_graph, crate_id, name.clone(), *krate);
486514
}
515+
rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
487516
}
488517
}
489-
// Now add a dep edge from all targets of upstream to the lib
490-
// target of downstream.
491-
for pkg in rustc_pkg_crates.keys().copied() {
492-
for dep in rustc_workspace[pkg].dependencies.iter() {
493-
let name = CrateName::new(&dep.name).unwrap();
494-
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
495-
for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
496-
add_dep(&mut crate_graph, from, name.clone(), to);
497-
}
498-
}
518+
}
519+
}
520+
// Now add a dep edge from all targets of upstream to the lib
521+
// target of downstream.
522+
for pkg in rustc_pkg_crates.keys().copied() {
523+
for dep in rustc_workspace[pkg].dependencies.iter() {
524+
let name = CrateName::new(&dep.name).unwrap();
525+
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
526+
for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
527+
add_dep(crate_graph, from, name.clone(), to);
499528
}
500529
}
501-
502-
// Add dependencies for all crates which opt in to rustc_private libraries
503-
for dep in rustc_workspace.packages() {
504-
let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
505-
506-
if let Some(&to) = pkg_to_lib_crate.get(&dep) {
507-
for pkg in cargo.packages() {
508-
let package = &cargo[pkg];
509-
if !package.metadata.rustc_private {
510-
continue;
511-
}
512-
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
513-
// Avoid creating duplicate dependencies
514-
if !crate_graph[from].dependencies.iter().any(|d| d.name == name) {
515-
add_dep(&mut crate_graph, from, name.clone(), to);
516-
} else {
517-
eprintln!(
518-
"Skipped {} for {:?}",
519-
&name, &crate_graph[from].display_name
520-
);
521-
}
522-
}
530+
}
531+
}
532+
// Add a dependency on the rustc_private crates for all targets of each package
533+
// which opts in
534+
for dep in rustc_workspace.packages() {
535+
let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
536+
537+
if let Some(&to) = pkg_to_lib_crate.get(&dep) {
538+
for pkg in cargo.packages() {
539+
let package = &cargo[pkg];
540+
if !package.metadata.rustc_private {
541+
continue;
542+
}
543+
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
544+
// Avoid creating duplicate dependencies
545+
// This avoids the situation where `from` depends on e.g. `arrayvec`, but
546+
// `rust_analyzer` thinks that it should use the one from the `rustcSource`
547+
// instead of the one from `crates.io`
548+
if !crate_graph[from].dependencies.iter().any(|d| d.name == name) {
549+
add_dep(crate_graph, from, name.clone(), to);
523550
}
524551
}
525552
}
526553
}
527554
}
528-
crate_graph
529555
}
530556

531557
fn add_target_crate_root(

0 commit comments

Comments
 (0)