@@ -5,7 +5,7 @@ use std::str::from_utf8;
5
5
6
6
use anyhow:: Context ;
7
7
use base_db:: Env ;
8
- use cargo_metadata:: { CargoOpt , MetadataCommand } ;
8
+ use cargo_metadata:: { CargoOpt , MetadataCommand , PackageId } ;
9
9
use la_arena:: { Arena , Idx } ;
10
10
use paths:: { AbsPath , AbsPathBuf , Utf8Path , Utf8PathBuf } ;
11
11
use rustc_hash:: { FxHashMap , FxHashSet } ;
@@ -14,6 +14,7 @@ use serde_json::from_value;
14
14
use span:: Edition ;
15
15
use stdx:: process:: spawn_with_streaming_output;
16
16
use toolchain:: Tool ;
17
+ use triomphe:: Arc ;
17
18
18
19
use crate :: cargo_config_file:: make_lockfile_copy;
19
20
use crate :: { CfgOverrides , InvocationStrategy } ;
@@ -155,8 +156,8 @@ pub struct PackageData {
155
156
pub features : FxHashMap < String , Vec < String > > ,
156
157
/// List of features enabled on this package
157
158
pub active_features : Vec < String > ,
158
- /// String representation of package id
159
- pub id : String ,
159
+ /// Package id
160
+ pub id : Arc < PackageId > ,
160
161
/// Authors as given in the `Cargo.toml`
161
162
pub authors : Vec < String > ,
162
163
/// Description as given in the `Cargo.toml`
@@ -173,6 +174,10 @@ pub struct PackageData {
173
174
pub rust_version : Option < semver:: Version > ,
174
175
/// The contents of [package.metadata.rust-analyzer]
175
176
pub metadata : RustAnalyzerPackageMetaData ,
177
+ /// If this is package is a member of the workspace, store all direct and transitive
178
+ /// dependencies as long as they are workspace members, to track dependency relationships
179
+ /// between members.
180
+ pub all_member_deps : Option < FxHashSet < Package > > ,
176
181
}
177
182
178
183
#[ derive( Deserialize , Default , Debug , Clone , Eq , PartialEq ) ]
@@ -334,6 +339,8 @@ impl CargoWorkspace {
334
339
let mut is_virtual_workspace = true ;
335
340
let mut requires_rustc_private = false ;
336
341
342
+ let mut members = FxHashSet :: default ( ) ;
343
+
337
344
meta. packages . sort_by ( |a, b| a. id . cmp ( & b. id ) ) ;
338
345
for meta_pkg in meta. packages {
339
346
let cargo_metadata:: Package {
@@ -356,6 +363,7 @@ impl CargoWorkspace {
356
363
rust_version,
357
364
..
358
365
} = meta_pkg;
366
+ let id = Arc :: new ( id) ;
359
367
let meta = from_value :: < PackageMetadata > ( metadata) . unwrap_or_default ( ) ;
360
368
let edition = match edition {
361
369
cargo_metadata:: Edition :: E2015 => Edition :: Edition2015 ,
@@ -375,7 +383,7 @@ impl CargoWorkspace {
375
383
let manifest = ManifestPath :: try_from ( AbsPathBuf :: assert ( manifest_path) ) . unwrap ( ) ;
376
384
is_virtual_workspace &= manifest != ws_manifest_path;
377
385
let pkg = packages. alloc ( PackageData {
378
- id : id. repr . clone ( ) ,
386
+ id : id. clone ( ) ,
379
387
name : name. to_string ( ) ,
380
388
version,
381
389
manifest : manifest. clone ( ) ,
@@ -395,7 +403,11 @@ impl CargoWorkspace {
395
403
features : features. into_iter ( ) . collect ( ) ,
396
404
active_features : Vec :: new ( ) ,
397
405
metadata : meta. rust_analyzer . unwrap_or_default ( ) ,
406
+ all_member_deps : None ,
398
407
} ) ;
408
+ if is_member {
409
+ members. insert ( pkg) ;
410
+ }
399
411
let pkg_data = & mut packages[ pkg] ;
400
412
requires_rustc_private |= pkg_data. metadata . rustc_private ;
401
413
pkg_by_id. insert ( id, pkg) ;
@@ -440,6 +452,43 @@ impl CargoWorkspace {
440
452
. extend ( node. features . into_iter ( ) . map ( |it| it. to_string ( ) ) ) ;
441
453
}
442
454
455
+ fn saturate_all_member_deps (
456
+ packages : & mut Arena < PackageData > ,
457
+ to_visit : Package ,
458
+ visited : & mut FxHashSet < Package > ,
459
+ members : & FxHashSet < Package > ,
460
+ ) {
461
+ let pkg_data = & mut packages[ to_visit] ;
462
+
463
+ if !visited. insert ( to_visit) {
464
+ return ;
465
+ }
466
+
467
+ let deps: Vec < _ > = pkg_data
468
+ . dependencies
469
+ . iter ( )
470
+ . filter_map ( |dep| {
471
+ let pkg = dep. pkg ;
472
+ if members. contains ( & pkg) { Some ( pkg) } else { None }
473
+ } )
474
+ . collect ( ) ;
475
+
476
+ let mut all_member_deps = FxHashSet :: from_iter ( deps. iter ( ) . copied ( ) ) ;
477
+ for dep in deps {
478
+ saturate_all_member_deps ( packages, dep, visited, members) ;
479
+ if let Some ( transitives) = & packages[ dep] . all_member_deps {
480
+ all_member_deps. extend ( transitives) ;
481
+ }
482
+ }
483
+
484
+ packages[ to_visit] . all_member_deps = Some ( all_member_deps) ;
485
+ }
486
+
487
+ let mut visited = FxHashSet :: default ( ) ;
488
+ for member in members. iter ( ) {
489
+ saturate_all_member_deps ( & mut packages, * member, & mut visited, & members) ;
490
+ }
491
+
443
492
CargoWorkspace {
444
493
packages,
445
494
targets,
0 commit comments