mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
fix(lsp): decode 'null' in server responses as vim.NIL #34849
Problem: Previously, 'null' value in LSP responses were decoded as 'nil'. This caused ambiguity for fields typed as '? | null' and led to loss of explicit 'null' values, particularly in 'data' parameters. Solution: Decode all JSON 'null' values as 'vim.NIL' and adjust handling where needed. This better aligns with the LSP specification, where 'null' and absent fields are distinct, and 'null' should not be used to represent missing values. This also enables proper validation of response messages to ensure that exactly one of 'result' or 'error' is present, as required by the JSON-RPC specification.
This commit is contained in:
@@ -323,7 +323,7 @@ end
|
||||
--- @package
|
||||
--- @param body string
|
||||
function Client:handle_body(body)
|
||||
local ok, decoded = pcall(vim.json.decode, body, { luanil = { object = true } })
|
||||
local ok, decoded = pcall(vim.json.decode, body)
|
||||
if not ok then
|
||||
self:on_error(M.client_errors.INVALID_SERVER_JSON, decoded)
|
||||
return
|
||||
@@ -355,7 +355,6 @@ function Client:handle_body(body)
|
||||
)
|
||||
end
|
||||
if err then
|
||||
---@cast err lsp.ResponseError
|
||||
assert(
|
||||
type(err) == 'table',
|
||||
'err must be a table. Use rpc_response_error to help format errors.'
|
||||
@@ -374,8 +373,16 @@ function Client:handle_body(body)
|
||||
end
|
||||
self:send_response(decoded.id, err, result)
|
||||
end))
|
||||
-- This works because we are expecting vim.NIL here
|
||||
elseif decoded.id and (decoded.result ~= vim.NIL or decoded.error ~= vim.NIL) then
|
||||
-- Proceed only if exactly one of 'result' or 'error' is present, as required by the LSP spec:
|
||||
-- - If 'error' is nil, then 'result' must be present.
|
||||
-- - If 'result' is nil, then 'error' must be present (and not vim.NIL).
|
||||
elseif
|
||||
decoded.id
|
||||
and (
|
||||
(decoded.error == nil and decoded.result ~= nil)
|
||||
or (decoded.result == nil and decoded.error ~= nil and decoded.error ~= vim.NIL)
|
||||
)
|
||||
then
|
||||
-- We sent a number, so we expect a number.
|
||||
local result_id = assert(tonumber(decoded.id), 'response id must be a number') --[[@as integer]]
|
||||
|
||||
@@ -415,7 +422,7 @@ function Client:handle_body(body)
|
||||
M.client_errors.SERVER_RESULT_CALLBACK_ERROR,
|
||||
callback,
|
||||
decoded.error,
|
||||
decoded.result
|
||||
decoded.result ~= vim.NIL and decoded.result or nil
|
||||
)
|
||||
else
|
||||
self:on_error(M.client_errors.NO_RESULT_CALLBACK_FOUND, decoded)
|
||||
|
Reference in New Issue
Block a user