lsp: Do not set error/result fields if they're missing. (#10610)

We were previously not conforming to LSP spec, as we were setting
**both** result field and error field on response fields, which could
confuse servers. Excerpt from the spec:
> * The result of a request. This member is REQUIRED on success.
> * This member MUST NOT exist if there was an error invoking the
method.

Fixes #10595

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2024-04-16 14:27:12 +02:00 committed by GitHub
parent 263023021d
commit e34c443331
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -138,8 +138,16 @@ struct AnyResponse<'a> {
struct Response<T> {
jsonrpc: &'static str,
id: RequestId,
result: Option<T>,
error: Option<Error>,
#[serde(flatten)]
value: LspResult<T>,
}
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
enum LspResult<T> {
#[serde(rename = "result")]
Ok(Option<T>),
Error(Option<Error>),
}
/// Language server protocol RPC notification message.
@ -867,16 +875,14 @@ impl LanguageServer {
Ok(result) => Response {
jsonrpc: JSON_RPC_VERSION,
id,
result: Some(result),
error: None,
value: LspResult::Ok(Some(result)),
},
Err(error) => Response {
jsonrpc: JSON_RPC_VERSION,
id,
result: None,
error: Some(Error {
value: LspResult::Error(Some(Error {
message: error.to_string(),
}),
})),
},
};
if let Some(response) =
@ -1503,4 +1509,27 @@ mod tests {
let expected_id = RequestId::Int(2);
assert_eq!(notification.id, Some(expected_id));
}
#[test]
fn test_serialize_has_no_nulls() {
// Ensure we're not setting both result and error variants. (ticket #10595)
let no_tag = Response::<u32> {
jsonrpc: "",
id: RequestId::Int(0),
value: LspResult::Ok(None),
};
assert_eq!(
serde_json::to_string(&no_tag).unwrap(),
"{\"jsonrpc\":\"\",\"id\":0,\"result\":null}"
);
let no_tag = Response::<u32> {
jsonrpc: "",
id: RequestId::Int(0),
value: LspResult::Error(None),
};
assert_eq!(
serde_json::to_string(&no_tag).unwrap(),
"{\"jsonrpc\":\"\",\"id\":0,\"error\":null}"
);
}
}