@@ -376,6 +376,7 @@ fn cargo_to_crate_graph(
376
376
cfg_options. insert_atom ( "debug_assertions" . into ( ) ) ;
377
377
378
378
let mut pkg_crates = FxHashMap :: default ( ) ;
379
+ // Does any crate signal to rust-analyzer that they need the rustc_private crates?
379
380
let mut has_private = false ;
380
381
// Next, create crates for each package, target pair
381
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
444
if has_private {
446
445
// If the user provided a path to rustc sources, we add all the rustc_private crates
447
446
// and create dependencies on them for the crates which opt-in to that
448
447
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) ;
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
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 ) ;
499
528
}
500
529
}
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) ;
523
550
}
524
551
}
525
552
}
526
553
}
527
554
}
528
- crate_graph
529
555
}
530
556
531
557
fn add_target_crate_root (
0 commit comments