Skip to content

Commit 5ddc828

Browse files
tolgacaglayantolgacaglayan
authored andcommitted
Delay missing-workspace warning until current-config fetch completes
1 parent 2532c48 commit 5ddc828

5 files changed

Lines changed: 89 additions & 19 deletions

File tree

crates/rust-analyzer/src/global_state.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use crate::{
5252
pub(crate) struct FetchWorkspaceRequest {
5353
pub(crate) path: Option<AbsPathBuf>,
5454
pub(crate) force_crate_graph_reload: bool,
55+
pub(crate) config_generation: u64,
5556
}
5657

5758
pub(crate) struct FetchWorkspaceResponse {
@@ -102,6 +103,8 @@ pub(crate) struct GlobalState {
102103
// status
103104
pub(crate) shutdown_requested: bool,
104105
pub(crate) last_reported_status: lsp_ext::ServerStatusParams,
106+
pub(crate) config_generation: u64,
107+
pub(crate) last_workspace_fetch_generation: Option<u64>,
105108

106109
// proc macros
107110
pub(crate) proc_macro_clients: Arc<[Option<anyhow::Result<ProcMacroClient>>]>,
@@ -277,6 +280,8 @@ impl GlobalState {
277280
quiescent: true,
278281
message: None,
279282
},
283+
config_generation: 0,
284+
last_workspace_fetch_generation: None,
280285
source_root_config: SourceRootConfig::default(),
281286
local_roots_parent_map: Arc::new(FxHashMap::default()),
282287
config_errors: Default::default(),
@@ -721,7 +726,11 @@ impl GlobalState {
721726

722727
self.fetch_ws_receiver = Some((
723728
crossbeam_channel::after(Duration::from_millis(100)),
724-
FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
729+
FetchWorkspaceRequest {
730+
path: Some(path),
731+
force_crate_graph_reload,
732+
config_generation: self.config_generation,
733+
},
725734
));
726735
}
727736

crates/rust-analyzer/src/handlers/notification.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ pub(crate) fn handle_did_save_text_document(
183183
FetchWorkspaceRequest {
184184
path: Some(path.to_owned()),
185185
force_crate_graph_reload: false,
186+
config_generation: state.config_generation,
186187
},
187188
);
188189
} else if state.detached_files.contains(path) {
@@ -191,6 +192,7 @@ pub(crate) fn handle_did_save_text_document(
191192
FetchWorkspaceRequest {
192193
path: Some(path.to_owned()),
193194
force_crate_graph_reload: false,
195+
config_generation: state.config_generation,
194196
},
195197
);
196198
}
@@ -278,7 +280,11 @@ pub(crate) fn handle_did_change_workspace_folders(
278280
if !config.has_linked_projects() && config.detached_files().is_empty() {
279281
config.rediscover_workspaces();
280282

281-
let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
283+
let req = FetchWorkspaceRequest {
284+
path: None,
285+
force_crate_graph_reload: false,
286+
config_generation: state.config_generation,
287+
};
282288
state.fetch_workspaces_queue.request_op("client workspaces changed".to_owned(), req);
283289
}
284290

crates/rust-analyzer/src/handlers/request.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow:
6161
state.proc_macro_clients = Arc::from_iter([]);
6262
state.build_deps_changed = false;
6363

64-
let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
64+
let req = FetchWorkspaceRequest {
65+
path: None,
66+
force_crate_graph_reload: false,
67+
config_generation: state.config_generation,
68+
};
6569
state.fetch_workspaces_queue.request_op("reload workspace request".to_owned(), req);
6670
Ok(())
6771
}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,18 @@ impl GlobalState {
192192
if self.config.discover_workspace_config().is_none() {
193193
self.fetch_workspaces_queue.request_op(
194194
"startup".to_owned(),
195-
FetchWorkspaceRequest { path: None, force_crate_graph_reload: false },
195+
FetchWorkspaceRequest {
196+
path: None,
197+
force_crate_graph_reload: false,
198+
config_generation: self.config_generation,
199+
},
196200
);
197-
if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
198-
self.fetch_workspaces_queue.should_start_op()
201+
if let Some((
202+
cause,
203+
FetchWorkspaceRequest { path, force_crate_graph_reload, config_generation },
204+
)) = self.fetch_workspaces_queue.should_start_op()
199205
{
200-
self.fetch_workspaces(cause, path, force_crate_graph_reload);
206+
self.fetch_workspaces(cause, path, force_crate_graph_reload, config_generation);
201207
}
202208
}
203209

@@ -564,10 +570,12 @@ impl GlobalState {
564570

565571
if (self.config.cargo_autoreload_config(None)
566572
|| self.config.discover_workspace_config().is_some())
567-
&& let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
568-
self.fetch_workspaces_queue.should_start_op()
573+
&& let Some((
574+
cause,
575+
FetchWorkspaceRequest { path, force_crate_graph_reload, config_generation },
576+
)) = self.fetch_workspaces_queue.should_start_op()
569577
{
570-
self.fetch_workspaces(cause, path, force_crate_graph_reload);
578+
self.fetch_workspaces(cause, path, force_crate_graph_reload, config_generation);
571579
}
572580

573581
if !self.fetch_workspaces_queue.op_in_progress() {
@@ -809,9 +817,14 @@ impl GlobalState {
809817
let (state, msg) = match progress {
810818
ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
811819
ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)),
812-
ProjectWorkspaceProgress::End(workspaces, force_crate_graph_reload) => {
820+
ProjectWorkspaceProgress::End(
821+
workspaces,
822+
force_crate_graph_reload,
823+
config_generation,
824+
) => {
813825
let resp = FetchWorkspaceResponse { workspaces, force_crate_graph_reload };
814826
self.fetch_workspaces_queue.op_completed(resp);
827+
self.last_workspace_fetch_generation = Some(config_generation);
815828
if let Err(e) = self.fetch_workspace_error() {
816829
error!("FetchWorkspaceError: {e}");
817830
}

crates/rust-analyzer/src/reload.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,19 @@ use crate::{
4444
};
4545
use 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)]
4856
pub(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?
954992
pub fn ws_to_crate_graph(
955993
workspaces: &[ProjectWorkspace],

0 commit comments

Comments
 (0)