@@ -44,11 +44,19 @@ use crate::{
4444} ;
4545use tracing:: { debug, info} ;
4646
47+ fn should_warn_missing_workspace (
48+ has_projects : bool ,
49+ has_detached_files : bool ,
50+ fetch_done_for_current_config : bool ,
51+ ) -> bool {
52+ fetch_done_for_current_config && !has_projects && !has_detached_files
53+ }
54+
4755#[ derive( Debug ) ]
4856pub ( crate ) enum ProjectWorkspaceProgress {
4957 Begin ,
5058 Report ( String ) ,
51- End ( Vec < anyhow:: Result < ProjectWorkspace > > , bool ) ,
59+ End ( Vec < anyhow:: Result < ProjectWorkspace > > , bool , u64 ) ,
5260}
5361
5462#[ derive( Debug ) ]
@@ -91,6 +99,7 @@ impl GlobalState {
9199
92100 pub ( crate ) fn update_configuration ( & mut self , config : Config ) {
93101 let _p = tracing:: info_span!( "GlobalState::update_configuration" ) . entered ( ) ;
102+ self . config_generation = self . config_generation . wrapping_add ( 1 ) ;
94103 let old_config = mem:: replace ( & mut self . config , Arc :: new ( config) ) ;
95104 if self . config . lru_parse_query_capacity ( ) != old_config. lru_parse_query_capacity ( ) {
96105 self . analysis_host . update_lru_capacity ( self . config . lru_parse_query_capacity ( ) ) ;
@@ -103,7 +112,11 @@ impl GlobalState {
103112
104113 if self . config . linked_or_discovered_projects ( ) != old_config. linked_or_discovered_projects ( )
105114 {
106- let req = FetchWorkspaceRequest { path : None , force_crate_graph_reload : false } ;
115+ let req = FetchWorkspaceRequest {
116+ path : None ,
117+ force_crate_graph_reload : false ,
118+ config_generation : self . config_generation ,
119+ } ;
107120 self . fetch_workspaces_queue . request_op ( "discovered projects changed" . to_owned ( ) , req)
108121 } else if self . config . flycheck ( None ) != old_config. flycheck ( None ) {
109122 self . reload_flycheck ( ) ;
@@ -119,12 +132,20 @@ impl GlobalState {
119132 }
120133
121134 if self . config . cargo ( None ) != old_config. cargo ( None ) {
122- let req = FetchWorkspaceRequest { path : None , force_crate_graph_reload : false } ;
135+ let req = FetchWorkspaceRequest {
136+ path : None ,
137+ force_crate_graph_reload : false ,
138+ config_generation : self . config_generation ,
139+ } ;
123140 self . fetch_workspaces_queue . request_op ( "cargo config changed" . to_owned ( ) , req)
124141 }
125142
126143 if self . config . cfg_set_test ( None ) != old_config. cfg_set_test ( None ) {
127- let req = FetchWorkspaceRequest { path : None , force_crate_graph_reload : false } ;
144+ let req = FetchWorkspaceRequest {
145+ path : None ,
146+ force_crate_graph_reload : false ,
147+ config_generation : self . config_generation ,
148+ } ;
128149 self . fetch_workspaces_queue . request_op ( "cfg_set_test config changed" . to_owned ( ) , req)
129150 }
130151 }
@@ -169,9 +190,11 @@ impl GlobalState {
169190 message. push ( '\n' ) ;
170191 }
171192
172- if self . config . linked_or_discovered_projects ( ) . is_empty ( )
173- && self . config . detached_files ( ) . is_empty ( )
174- {
193+ if should_warn_missing_workspace (
194+ self . config . linked_or_discovered_projects ( ) . is_empty ( ) ,
195+ self . config . detached_files ( ) . is_empty ( ) ,
196+ self . last_workspace_fetch_generation == Some ( self . config_generation ) ,
197+ ) {
175198 status. health |= lsp_ext:: Health :: Warning ;
176199 message. push_str ( "Failed to discover workspace.\n " ) ;
177200 message. push_str ( "Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/book/configuration.html#linkedProjects) setting.\n \n " ) ;
@@ -284,6 +307,7 @@ impl GlobalState {
284307 cause : Cause ,
285308 path : Option < AbsPathBuf > ,
286309 force_crate_graph_reload : bool ,
310+ config_generation : u64 ,
287311 ) {
288312 info ! ( %cause, "will fetch workspaces" ) ;
289313
@@ -380,6 +404,7 @@ impl GlobalState {
380404 . send ( Task :: FetchWorkspace ( ProjectWorkspaceProgress :: End (
381405 workspaces,
382406 force_crate_graph_reload,
407+ config_generation,
383408 ) ) )
384409 . unwrap ( ) ;
385410 }
@@ -472,7 +497,7 @@ impl GlobalState {
472497 let _p = tracing:: info_span!( "GlobalState::switch_workspaces" ) . entered ( ) ;
473498 tracing:: info!( %cause, "will switch workspaces" ) ;
474499
475- let Some ( FetchWorkspaceResponse { workspaces, force_crate_graph_reload } ) =
500+ let Some ( FetchWorkspaceResponse { workspaces, force_crate_graph_reload, .. } ) =
476501 self . fetch_workspaces_queue . last_op_result ( )
477502 else {
478503 return ;
@@ -950,6 +975,19 @@ impl GlobalState {
950975 }
951976}
952977
978+ #[ cfg( test) ]
979+ mod tests {
980+ use super :: should_warn_missing_workspace;
981+
982+ #[ test]
983+ fn missing_workspace_warning_is_gated_by_fetch_completion ( ) {
984+ assert ! ( !should_warn_missing_workspace( false , false , false ) ) ;
985+ assert ! ( should_warn_missing_workspace( false , false , true ) ) ;
986+ assert ! ( !should_warn_missing_workspace( true , false , true ) ) ;
987+ assert ! ( !should_warn_missing_workspace( false , true , true ) ) ;
988+ }
989+ }
990+
953991// FIXME: Move this into load-cargo?
954992pub fn ws_to_crate_graph (
955993 workspaces : & [ ProjectWorkspace ] ,
0 commit comments