diff options
-rw-r--r-- | crates/project_model/src/workspace.rs | 170 |
1 files changed, 98 insertions, 72 deletions
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( | |||
376 | cfg_options.insert_atom("debug_assertions".into()); | 376 | cfg_options.insert_atom("debug_assertions".into()); |
377 | 377 | ||
378 | let mut pkg_crates = FxHashMap::default(); | 378 | let mut pkg_crates = FxHashMap::default(); |
379 | // Does any crate signal to rust-analyzer that they need the rustc_private crates? | ||
379 | let mut has_private = false; | 380 | let mut has_private = false; |
380 | // Next, create crates for each package, target pair | 381 | // Next, create crates for each package, target pair |
381 | for pkg in cargo.packages() { | 382 | for pkg in cargo.packages() { |
@@ -440,92 +441,117 @@ fn cargo_to_crate_graph( | |||
440 | } | 441 | } |
441 | } | 442 | } |
442 | 443 | ||
443 | let mut rustc_pkg_crates = FxHashMap::default(); | ||
444 | |||
445 | if has_private { | 444 | if has_private { |
446 | // If the user provided a path to rustc sources, we add all the rustc_private crates | 445 | // If the user provided a path to rustc sources, we add all the rustc_private crates |
447 | // and create dependencies on them for the crates which opt-in to that | 446 | // and create dependencies on them for the crates which opt-in to that |
448 | if let Some(rustc_workspace) = rustc { | 447 | if let Some(rustc_workspace) = rustc { |
449 | // rustc-dev crates start from 'rustc_driver' | 448 | handle_rustc_crates( |
450 | // We want to collect all crates which are transitive dependencies of rustc_driver | 449 | rustc_workspace, |
451 | if let Some(root_pkg) = rustc_workspace | 450 | load, |
452 | .packages() | 451 | &mut crate_graph, |
453 | .find(|package| rustc_workspace[*package].name == "rustc_driver") | 452 | rustc_build_data_map, |
454 | { | 453 | &cfg_options, |
455 | let mut queue = VecDeque::new(); | 454 | proc_macro_loader, |
456 | queue.push_back(root_pkg); | 455 | &mut pkg_to_lib_crate, |
457 | while let Some(pkg) = queue.pop_front() { | 456 | &public_deps, |
458 | // Don't duplicate packages | 457 | cargo, |
459 | if rustc_pkg_crates.contains_key(&pkg) { | 458 | &pkg_crates, |
460 | continue; | 459 | ); |
461 | } | 460 | } |
462 | for dep in &rustc_workspace[pkg].dependencies { | 461 | } |
463 | queue.push_back(dep.pkg); | 462 | crate_graph |
464 | } | 463 | } |
465 | for &tgt in rustc_workspace[pkg].targets.iter() { | 464 | |
466 | if rustc_workspace[tgt].kind != TargetKind::Lib { | 465 | fn handle_rustc_crates( |
467 | continue; | 466 | rustc_workspace: &CargoWorkspace, |
468 | } | 467 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
469 | if let Some(file_id) = load(&rustc_workspace[tgt].root) { | 468 | crate_graph: &mut CrateGraph, |
470 | let crate_id = add_target_crate_root( | 469 | rustc_build_data_map: Option<&FxHashMap<String, BuildData>>, |
471 | &mut crate_graph, | 470 | cfg_options: &CfgOptions, |
472 | &rustc_workspace[pkg], | 471 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
473 | rustc_build_data_map | 472 | pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>, |
474 | .and_then(|it| it.get(&rustc_workspace[pkg].id)), | 473 | public_deps: &[(CrateName, CrateId)], |
475 | &cfg_options, | 474 | cargo: &CargoWorkspace, |
476 | proc_macro_loader, | 475 | pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<CrateId>>, |
477 | file_id, | 476 | ) { |
478 | ); | 477 | let mut rustc_pkg_crates = FxHashMap::default(); |
479 | pkg_to_lib_crate.insert(pkg, crate_id); | 478 | // The root package of the rustc-dev component is rustc_driver, so we match that |
480 | // Add dependencies on the core / std / alloc for rustc | 479 | let root_pkg = |
481 | for (name, krate) in public_deps.iter() { | 480 | rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver"); |
482 | add_dep(&mut crate_graph, crate_id, name.clone(), *krate); | 481 | // The rustc workspace might be incomplete (such as if rustc-dev is not installed for the current toolchain) |
483 | } | 482 | // and `rustcSource` is set to discover. |
484 | rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | 483 | if let Some(root_pkg) = root_pkg { |
485 | } | 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); | ||
486 | } | 514 | } |
515 | rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
487 | } | 516 | } |
488 | } | 517 | } |
489 | // Now add a dep edge from all targets of upstream to the lib | 518 | } |
490 | // target of downstream. | 519 | } |
491 | for pkg in rustc_pkg_crates.keys().copied() { | 520 | // Now add a dep edge from all targets of upstream to the lib |
492 | for dep in rustc_workspace[pkg].dependencies.iter() { | 521 | // target of downstream. |
493 | let name = CrateName::new(&dep.name).unwrap(); | 522 | for pkg in rustc_pkg_crates.keys().copied() { |
494 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | 523 | for dep in rustc_workspace[pkg].dependencies.iter() { |
495 | for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { | 524 | let name = CrateName::new(&dep.name).unwrap(); |
496 | add_dep(&mut crate_graph, from, name.clone(), to); | 525 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { |
497 | } | 526 | for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { |
498 | } | 527 | add_dep(crate_graph, from, name.clone(), to); |
499 | } | 528 | } |
500 | } | 529 | } |
501 | 530 | } | |
502 | // Add dependencies for all crates which opt in to rustc_private libraries | 531 | } |
503 | for dep in rustc_workspace.packages() { | 532 | // Add a dependency on the rustc_private crates for all targets of each package |
504 | let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); | 533 | // which opts in |
505 | 534 | for dep in rustc_workspace.packages() { | |
506 | if let Some(&to) = pkg_to_lib_crate.get(&dep) { | 535 | let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); |
507 | for pkg in cargo.packages() { | 536 | |
508 | let package = &cargo[pkg]; | 537 | if let Some(&to) = pkg_to_lib_crate.get(&dep) { |
509 | if !package.metadata.rustc_private { | 538 | for pkg in cargo.packages() { |
510 | continue; | 539 | let package = &cargo[pkg]; |
511 | } | 540 | if !package.metadata.rustc_private { |
512 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | 541 | continue; |
513 | // Avoid creating duplicate dependencies | 542 | } |
514 | if !crate_graph[from].dependencies.iter().any(|d| d.name == name) { | 543 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { |
515 | add_dep(&mut crate_graph, from, name.clone(), to); | 544 | // Avoid creating duplicate dependencies |
516 | } else { | 545 | // This avoids the situation where `from` depends on e.g. `arrayvec`, but |
517 | eprintln!( | 546 | // `rust_analyzer` thinks that it should use the one from the `rustcSource` |
518 | "Skipped {} for {:?}", | 547 | // instead of the one from `crates.io` |
519 | &name, &crate_graph[from].display_name | 548 | if !crate_graph[from].dependencies.iter().any(|d| d.name == name) { |
520 | ); | 549 | add_dep(crate_graph, from, name.clone(), to); |
521 | } | ||
522 | } | ||
523 | } | 550 | } |
524 | } | 551 | } |
525 | } | 552 | } |
526 | } | 553 | } |
527 | } | 554 | } |
528 | crate_graph | ||
529 | } | 555 | } |
530 | 556 | ||
531 | fn add_target_crate_root( | 557 | fn add_target_crate_root( |