diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index ab045e0bf9ff..9bcf835b4cca 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -208,13 +208,24 @@ fn run_server() -> anyhow::Result<()> { tracing::info!("InitializeParams: {}", initialize_params); let lsp_types::InitializeParams { root_uri, - capabilities, + mut capabilities, workspace_folders, initialization_options, client_info, .. } = from_json::("InitializeParams", &initialize_params)?; + // lsp-types has a typo in the `/capabilities/workspace/diagnostics` field, its typoed as `diagnostic` + if let Some(val) = initialize_params.pointer("/capabilities/workspace/diagnostics") { + if let Ok(diag_caps) = from_json::( + "DiagnosticWorkspaceClientCapabilities", + val, + ) { + tracing::info!("Patching lsp-types workspace diagnostics capabilities: {diag_caps:#?}"); + capabilities.workspace.get_or_insert_default().diagnostic.get_or_insert(diag_caps); + } + } + let root_path = match root_uri .and_then(|it| it.to_file_path().ok()) .map(patch_path_prefix) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 2f1afba3634e..89d6fb8edc2e 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -183,6 +183,10 @@ pub(crate) struct GlobalState { /// this queue should run only *after* [`GlobalState::process_changes`] has /// been called. pub(crate) deferred_task_queue: TaskQueue, + /// HACK: Workaround for https://github.com/rust-lang/rust-analyzer/issues/19709 + /// This is marked true if we failed to load a crate root file at crate graph creation, + /// which will usually end up causing a bunch of incorrect diagnostics on startup. + pub(crate) incomplete_crate_graph: bool, } /// An immutable snapshot of the world's state at a point in time. @@ -298,6 +302,7 @@ impl GlobalState { discover_workspace_queue: OpQueue::default(), deferred_task_queue: task_queue, + incomplete_crate_graph: false, }; // Apply any required database inputs from the config. this.update_configuration(config); diff --git a/crates/rust-analyzer/src/handlers/dispatch.rs b/crates/rust-analyzer/src/handlers/dispatch.rs index b25245dd884a..10bbb0bb31d9 100644 --- a/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/crates/rust-analyzer/src/handlers/dispatch.rs @@ -141,7 +141,7 @@ impl RequestDispatcher<'_> { Result: Serialize, > + 'static, { - if !self.global_state.vfs_done { + if !self.global_state.vfs_done || self.global_state.incomplete_crate_graph { if let Some(lsp_server::Request { id, .. }) = self.req.take_if(|it| it.method == R::METHOD) { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index aa38aa72d44e..def08053f1ee 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -739,13 +739,16 @@ impl GlobalState { }) .collect(); + self.incomplete_crate_graph = false; let (crate_graph, proc_macro_paths) = { // Create crate graph from all the workspaces let vfs = &self.vfs.read().0; let load = |path: &AbsPath| { let vfs_path = vfs::VfsPath::from(path.to_path_buf()); self.crate_graph_file_dependencies.insert(vfs_path.clone()); - vfs.file_id(&vfs_path).and_then(|(file_id, excluded)| { + let file_id = vfs.file_id(&vfs_path); + self.incomplete_crate_graph |= file_id.is_none(); + file_id.and_then(|(file_id, excluded)| { (excluded == vfs::FileExcluded::No).then_some(file_id) }) };