neovim / neovim

Vim-fork focused on extensibility and usability
https://neovim.io
Other
79.84k stars 5.5k forks source link

LSP: tolerate invalid paths in locations_to_items #28281

Open chenf7 opened 2 months ago

chenf7 commented 2 months ago

Problem

I sometimes get an error when trying to go to definition of find code references. When the error occurs I get no results (no quick fix list). However, when checking the LspLog I see that a list of results is returned. The list of results from LSP contains some non existing paths. The source of the problem is probably somewhere between sourcekit-lsp itself and my configuration files for the iOS project. However, I see no reason to give up on some of the correct results in the list just because of a few bad apples in it.

This is the error:

Error executing vim.schedule lua callback: ...lar/neovim/0.9.4/share/nvim/runtime/lua/vim/lsp/util.lua:1828: index out of range
stack traceback:
        [C]: in function '_str_byteindex_enc'
        ...lar/neovim/0.9.4/share/nvim/runtime/lua/vim/lsp/util.lua:1828: in function 'locations_to_items'
        ...neovim/0.9.4/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        ...w/Cellar/neovim/0.9.4/share/nvim/runtime/lua/vim/lsp.lua:1393: in function 'cb'
        vim/_editor.lua:263: in function <vim/_editor.lua:262>

I propose to tolerate errors and just report them to the user. And this can also be put behind some config flag if ignoring errors feels to outrageous. In runtime/lua/vim/lsp/util.lua, in function M.locations_to_items:

      local callOk, col = pcall(M._str_byteindex_enc, line, pos.character, offset_encoding)
      if callOk then
        table.insert(items, {
          filename = filename,
          lnum = row + 1,
          col = col + 1,
          text = line,
          user_data = temp.location,
        })
      else
        -- errorCount will be defined above, outside of the for loop
        errorCount = errorCount + 1
      end
    end
    -- out of for loop. notify on found errors
    if errorCount > 0 then
      print("Error found when processing LSP RPC.......")
    end

Steps to reproduce using "nvim -u minimal_init.lua"

In the unlikely scenario of working on an iOS xcworkspace with multiple xcodeproj projects and pod dependencies, Run either vim.lsp.buf.definition or vim.lsp.buf.references lua functions.

Expected behavior

No response

Neovim version (nvim -v)

0.9.4

Language server name/version

sourcekit

Operating system/version

macOS 14.4.1

Log file

No response

justinmk commented 2 months ago

Thanks for the report. Can you try the development version?

chenf7 commented 2 months ago

Hi @justinmk , it still happens on NVIM v0.10.0-dev-2913+g5371ed36b

glepnir commented 2 months ago

Please provide a minimal detailed steps to reproduce

stasjok commented 3 weeks ago

Please provide a minimal detailed steps to reproduce

Hey, maybe it's not exactly the same issue, but locations_to_items (which is used in vim.lsp.buf.definition function) also is not tolerating ranges which go beyond line length.

LSP spec states that "if the character value is greater than the line length it defaults back to the line length", but locations_to_items gives the error in that case.

Here is a reproducer. minimal_init.lua:

---Definition provider, returns static result
---@param uri string
---@return lsp.Definition
local function go_to_definition(uri)
  ---@type lsp.Definition
  local result = {
    -- Document start
    {
      uri = uri,
      range = { start = { line = 0, character = 0 }, ["end"] = { line = 0, character = 0 } },
    },
    -- More than line length
    {
      uri = uri,
      range = { start = { line = 1, character = 1000 }, ["end"] = { line = 1, character = 1000 } },
    },
  }
  return result
end

---Fake LSP server
---@param dispatchers vim.lsp.rpc.Dispatchers
---@return vim.lsp.rpc.PublicClient
local function fake_server(dispatchers)
  local request_id = 0

  ---@type vim.lsp.rpc.PublicClient
  local client = {
    request = function(method, params, callback, notify_reply_callback)
      request_id = request_id + 1

      local function response(result)
        vim.schedule(function()
          if notify_reply_callback then
            notify_reply_callback(request_id)
          end
          callback(nil, result)
        end)
      end

      -- Initialization
      if method == vim.lsp.protocol.Methods.initialize then
        ---@type lsp.InitializeResult
        local result = { capabilities = { definitionProvider = true } }
        response(result)

      -- Goto Definition Request
      elseif method == vim.lsp.protocol.Methods.textDocument_definition then
        ---@cast params lsp.DefinitionParams
        response(go_to_definition(params.textDocument.uri))
      else
        return false
      end

      return true, request_id
    end,

    notify = function(method, params)
      return true
    end,

    is_closing = function()
      return false
    end,

    terminate = function()
      dispatchers.on_exit(0, 0)
    end,
  }
  return client
end

-- Start LSP client
vim.api.nvim_create_autocmd("BufEnter", {
  callback = function()
    vim.lsp.start({
      cmd = fake_server,
    })
  end,
})

-- Go to definition mapping
vim.keymap.set("n", "gd", vim.lsp.buf.definition)

It uses dummy client, that always returns static go to definition responses. One is at zero document position, second with character parameter that is greater than line length.

To use it, run neovim: nvim --clean --noplugin -u minimal_init.lua minimal_init.lua, then run command :lua vim.lsp.buf.definition() or use gd mapping anywhere in a document. Instead of showing LSP locations it errors with index out of range issue:

Error executing vim.schedule lua callback: ...nvim.a8t6Rav/usr/share/nvim/runtime/lua/vim/lsp/util.lua:1802: index out 
of range                                                                                                               
stack traceback:                                                                                                       
        [C]: in function '_str_byteindex_enc'                                                                          
        ...nvim.a8t6Rav/usr/share/nvim/runtime/lua/vim/lsp/util.lua:1802: in function 'locations_to_items'             
        ....a8t6Rav/usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:436: in function 'handler'                         
        ...im.a8t6Rav/usr/share/nvim/runtime/lua/vim/lsp/client.lua:687: in function 'callback'                        
        /home/stas/other/reproducers/minimal_init.lua:37: in function </home/stas/other/reproducers/minimal_init.lua:33