@@ -27,6 +27,7 @@ use ide_db::{
27
27
use itertools:: Itertools ;
28
28
use proc_macro_api:: { MacroDylib , ProcMacroServer } ;
29
29
use project_model:: { PackageRoot , ProjectWorkspace , WorkspaceBuildScripts } ;
30
+ use rustc_hash:: FxHashSet ;
30
31
use stdx:: { format_to, thread:: ThreadIntent } ;
31
32
use syntax:: SmolStr ;
32
33
use triomphe:: Arc ;
@@ -46,7 +47,7 @@ use ::tt::token_id as tt;
46
47
pub ( crate ) enum ProjectWorkspaceProgress {
47
48
Begin ,
48
49
Report ( String ) ,
49
- End ( Vec < anyhow:: Result < ProjectWorkspace > > ) ,
50
+ End ( Vec < anyhow:: Result < ProjectWorkspace > > , bool ) ,
50
51
}
51
52
52
53
#[ derive( Debug ) ]
@@ -85,7 +86,7 @@ impl GlobalState {
85
86
) ;
86
87
}
87
88
if self . config . linked_projects ( ) != old_config. linked_projects ( ) {
88
- self . fetch_workspaces_queue . request_op ( "linked projects changed" . to_string ( ) , ( ) )
89
+ self . fetch_workspaces_queue . request_op ( "linked projects changed" . to_string ( ) , false )
89
90
} else if self . config . flycheck ( ) != old_config. flycheck ( ) {
90
91
self . reload_flycheck ( ) ;
91
92
}
@@ -182,7 +183,7 @@ impl GlobalState {
182
183
status
183
184
}
184
185
185
- pub ( crate ) fn fetch_workspaces ( & mut self , cause : Cause ) {
186
+ pub ( crate ) fn fetch_workspaces ( & mut self , cause : Cause , force_crate_graph_reload : bool ) {
186
187
tracing:: info!( %cause, "will fetch workspaces" ) ;
187
188
188
189
self . task_pool . handle . spawn_with_sender ( ThreadIntent :: Worker , {
@@ -250,7 +251,10 @@ impl GlobalState {
250
251
251
252
tracing:: info!( "did fetch workspaces {:?}" , workspaces) ;
252
253
sender
253
- . send ( Task :: FetchWorkspace ( ProjectWorkspaceProgress :: End ( workspaces) ) )
254
+ . send ( Task :: FetchWorkspace ( ProjectWorkspaceProgress :: End (
255
+ workspaces,
256
+ force_crate_graph_reload,
257
+ ) ) )
254
258
. unwrap ( ) ;
255
259
}
256
260
} ) ;
@@ -336,15 +340,19 @@ impl GlobalState {
336
340
let _p = profile:: span ( "GlobalState::switch_workspaces" ) ;
337
341
tracing:: info!( %cause, "will switch workspaces" ) ;
338
342
343
+ let Some ( ( workspaces, force_reload_crate_graph) ) = self . fetch_workspaces_queue . last_op_result ( ) else { return ; } ;
344
+
339
345
if let Err ( _) = self . fetch_workspace_error ( ) {
340
346
if !self . workspaces . is_empty ( ) {
347
+ if * force_reload_crate_graph {
348
+ self . recreate_crate_graph ( cause) ;
349
+ }
341
350
// It only makes sense to switch to a partially broken workspace
342
351
// if we don't have any workspace at all yet.
343
352
return ;
344
353
}
345
354
}
346
355
347
- let Some ( workspaces) = self . fetch_workspaces_queue . last_op_result ( ) else { return ; } ;
348
356
let workspaces =
349
357
workspaces. iter ( ) . filter_map ( |res| res. as_ref ( ) . ok ( ) . cloned ( ) ) . collect :: < Vec < _ > > ( ) ;
350
358
@@ -373,6 +381,9 @@ impl GlobalState {
373
381
self . workspaces = Arc :: new ( workspaces) ;
374
382
} else {
375
383
tracing:: info!( "build scripts do not match the version of the active workspace" ) ;
384
+ if * force_reload_crate_graph {
385
+ self . recreate_crate_graph ( cause) ;
386
+ }
376
387
// Current build scripts do not match the version of the active
377
388
// workspace, so there's nothing for us to update.
378
389
return ;
@@ -467,13 +478,24 @@ impl GlobalState {
467
478
} ) ;
468
479
self . source_root_config = project_folders. source_root_config ;
469
480
481
+ self . recreate_crate_graph ( cause) ;
482
+
483
+ tracing:: info!( "did switch workspaces" ) ;
484
+ }
485
+
486
+ fn recreate_crate_graph ( & mut self , cause : String ) {
470
487
// Create crate graph from all the workspaces
471
- let ( crate_graph, proc_macro_paths) = {
488
+ let ( crate_graph, proc_macro_paths, crate_graph_file_dependencies ) = {
472
489
let vfs = & mut self . vfs . write ( ) . 0 ;
473
490
let loader = & mut self . loader ;
491
+ // crate graph construction relies on these paths, record them so when one of them gets
492
+ // deleted or created we trigger a reconstruction of the crate graph
493
+ let mut crate_graph_file_dependencies = FxHashSet :: default ( ) ;
494
+
474
495
let mut load = |path : & AbsPath | {
475
496
let _p = profile:: span ( "switch_workspaces::load" ) ;
476
497
let vfs_path = vfs:: VfsPath :: from ( path. to_path_buf ( ) ) ;
498
+ crate_graph_file_dependencies. insert ( vfs_path. clone ( ) ) ;
477
499
match vfs. file_id ( & vfs_path) {
478
500
Some ( file_id) => Some ( file_id) ,
479
501
None => {
@@ -494,26 +516,25 @@ impl GlobalState {
494
516
crate_graph. extend ( other, & mut crate_proc_macros) ;
495
517
proc_macros. push ( crate_proc_macros) ;
496
518
}
497
- ( crate_graph, proc_macros)
519
+ ( crate_graph, proc_macros, crate_graph_file_dependencies )
498
520
} ;
499
- let mut change = Change :: new ( ) ;
500
521
501
522
if self . config . expand_proc_macros ( ) {
502
523
self . fetch_proc_macros_queue . request_op ( cause, proc_macro_paths) ;
503
524
}
525
+ let mut change = Change :: new ( ) ;
504
526
change. set_crate_graph ( crate_graph) ;
505
527
self . analysis_host . apply_change ( change) ;
528
+ self . crate_graph_file_dependencies = crate_graph_file_dependencies;
506
529
self . process_changes ( ) ;
507
530
508
531
self . reload_flycheck ( ) ;
509
-
510
- tracing:: info!( "did switch workspaces" ) ;
511
532
}
512
533
513
534
pub ( super ) fn fetch_workspace_error ( & self ) -> Result < ( ) , String > {
514
535
let mut buf = String :: new ( ) ;
515
536
516
- let Some ( last_op_result) = self . fetch_workspaces_queue . last_op_result ( ) else { return Ok ( ( ) ) } ;
537
+ let Some ( ( last_op_result, _ ) ) = self . fetch_workspaces_queue . last_op_result ( ) else { return Ok ( ( ) ) } ;
517
538
if last_op_result. is_empty ( ) {
518
539
stdx:: format_to!( buf, "rust-analyzer failed to discover workspace" ) ;
519
540
} else {
0 commit comments