From 865904a0c951e84aea71cd1962f133cb3db1824f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:49:11 +0200 Subject: [PATCH] lsp: Pass back diagnostic .data when querying code actions for it (#14962) Per the LSP spec, we should pass .data field of diagnostics into code action request: ``` /** * A data entry field that is preserved between a * `textDocument/publishDiagnostics` notification and * `textDocument/codeAction` request. * * @since 3.16.0 */ data?: LSPAny; ``` Release Notes: - Fixed rare cases where a code action triggered by diagnostic may not be available for use. --- crates/diagnostics/src/diagnostics_tests.rs | 1 + crates/language/src/buffer.rs | 4 ++++ crates/language/src/diagnostic_set.rs | 1 + crates/language/src/proto.rs | 10 +++++++++- crates/project/src/project.rs | 2 ++ crates/proto/proto/zed.proto | 1 + 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/diagnostics/src/diagnostics_tests.rs b/crates/diagnostics/src/diagnostics_tests.rs index 32f40edc1c..c05dff5a69 100644 --- a/crates/diagnostics/src/diagnostics_tests.rs +++ b/crates/diagnostics/src/diagnostics_tests.rs @@ -954,6 +954,7 @@ fn random_diagnostic( is_primary, is_disk_based: false, is_unnecessary: false, + data: None, }, } } diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 6251e77250..b4a8649c8d 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -27,6 +27,7 @@ use gpui::{ use lazy_static::lazy_static; use lsp::LanguageServerId; use parking_lot::Mutex; +use serde_json::Value; use similar::{ChangeTag, TextDiff}; use smallvec::SmallVec; use smol::future::yield_now; @@ -213,6 +214,8 @@ pub struct Diagnostic { pub is_disk_based: bool, /// Whether this diagnostic marks unnecessary code. pub is_unnecessary: bool, + /// Data from language server that produced this diagnostic. Passed back to the LS when we request code actions for this diagnostic. + pub data: Option, } /// TODO - move this into the `project` crate and make it private. @@ -3844,6 +3847,7 @@ impl Default for Diagnostic { is_primary: false, is_disk_based: false, is_unnecessary: false, + data: None, } } } diff --git a/crates/language/src/diagnostic_set.rs b/crates/language/src/diagnostic_set.rs index ea35bc184c..c0d4c27a76 100644 --- a/crates/language/src/diagnostic_set.rs +++ b/crates/language/src/diagnostic_set.rs @@ -69,6 +69,7 @@ impl DiagnosticEntry { severity: Some(self.diagnostic.severity), source: self.diagnostic.source.clone(), message: self.diagnostic.message.clone(), + data: self.diagnostic.data.clone(), ..Default::default() } } diff --git a/crates/language/src/proto.rs b/crates/language/src/proto.rs index f2634b4285..94b720c1fd 100644 --- a/crates/language/src/proto.rs +++ b/crates/language/src/proto.rs @@ -5,7 +5,8 @@ use anyhow::{anyhow, Context as _, Result}; use clock::ReplicaId; use lsp::{DiagnosticSeverity, LanguageServerId}; use rpc::proto; -use std::{ops::Range, sync::Arc}; +use serde_json::Value; +use std::{ops::Range, str::FromStr, sync::Arc}; use text::*; pub use proto::{BufferState, Operation}; @@ -213,6 +214,7 @@ pub fn serialize_diagnostics<'a>( code: entry.diagnostic.code.clone(), is_disk_based: entry.diagnostic.is_disk_based, is_unnecessary: entry.diagnostic.is_unnecessary, + data: entry.diagnostic.data.as_ref().map(|data| data.to_string()), }) .collect() } @@ -396,6 +398,11 @@ pub fn deserialize_diagnostics( diagnostics .into_iter() .filter_map(|diagnostic| { + let data = if let Some(data) = diagnostic.data { + Some(Value::from_str(&data).ok()?) + } else { + None + }; Some(DiagnosticEntry { range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?, diagnostic: Diagnostic { @@ -413,6 +420,7 @@ pub fn deserialize_diagnostics( is_primary: diagnostic.is_primary, is_disk_based: diagnostic.is_disk_based, is_unnecessary: diagnostic.is_unnecessary, + data, }, }) }) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 07d2f528c1..54b38717f1 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -4595,6 +4595,7 @@ impl Project { is_primary: true, is_disk_based, is_unnecessary, + data: diagnostic.data.clone(), }, }); if let Some(infos) = &diagnostic.related_information { @@ -4612,6 +4613,7 @@ impl Project { is_primary: false, is_disk_based, is_unnecessary: false, + data: diagnostic.data.clone(), }, }); } diff --git a/crates/proto/proto/zed.proto b/crates/proto/proto/zed.proto index b2f652052e..f4893a5579 100644 --- a/crates/proto/proto/zed.proto +++ b/crates/proto/proto/zed.proto @@ -1890,6 +1890,7 @@ message Diagnostic { Information = 3; Hint = 4; } + optional string data = 12; } message Operation {