neovim / nvim-lspconfig

Quickstart configs for Nvim LSP
Apache License 2.0
10.62k stars 2.08k forks source link

clangd based lsp cannot find "nested" include files #1888

Closed JacekHoleczek closed 2 years ago

JacekHoleczek commented 2 years ago

Description

I am having problems in NVIM with "#include" files that are "not found".

Please find below a minimal "reproducer".

mkdir -p /tmp/trial/include/XY /tmp/trial/src
echo -e '#include "XY/Y.hxx"' > /tmp/trial/include/XY/X.hxx
touch /tmp/trial/include/XY/Y.hxx # can be completely empty
cd /tmp/trial/src
echo -e '--language=c++\n-I/tmp/trial/include' > compile_flags.txt
echo -e '#include "XY/X.hxx"\nint main() {return 0;}' > main.cxx
clangd --check=main.cxx # no problems here
nvim main.cxx # try to "gd" or "gD" for "XY/X.hxx"

While editing the "main.cxx" file, when one executes "gd" or "gD" (i.e. "vim.lsp.buf.definition" or "vim.lsp.buf.declaration") for the included "XY/X.hxx" file, it will open this file but then it immediately reports an error: 'XY/Y.hxx' file not found

Neovim version

NVIM v0.6.1 Build type: Release LuaJIT 2.1.0-beta3 Compiled by runner@fv-az87-780

Nvim-lspconfig version

No response

Operating system and version

Linux x86_64

Affected language servers

clangd 14.0.0

Steps to reproduce

See the minimal "reproducer" in the "Description" above.

Actual behavior

clangd based lsp cannot find "nested" include files

Expected behavior

No response

Minimal config

local on_windows = vim.loop.os_uname().version:match 'Windows'

local function join_paths(...)
  local path_sep = on_windows and '\\' or '/'
  local result = table.concat({ ... }, path_sep)
  return result
end

vim.cmd [[set runtimepath=$VIMRUNTIME]]

local temp_dir = vim.loop.os_getenv 'TEMP' or '/tmp'

vim.cmd('set packpath=' .. join_paths(temp_dir, 'nvim', 'site'))

local package_root = join_paths(temp_dir, 'nvim', 'site', 'pack')
local install_path = join_paths(package_root, 'packer', 'start', 'packer.nvim')
local compile_path = join_paths(install_path, 'plugin', 'packer_compiled.lua')

local function load_plugins()
  require('packer').startup {
    {
      'wbthomason/packer.nvim',
      'neovim/nvim-lspconfig',
    },
    config = {
      package_root = package_root,
      compile_path = compile_path,
    },
  }
end

_G.load_config = function()
  vim.lsp.set_log_level 'trace'
  if vim.fn.has 'nvim-0.5.1' == 1 then
    require('vim.lsp.log').set_format_func(vim.inspect)
  end
  local nvim_lsp = require 'lspconfig'
  local on_attach = function(_, bufnr)
    local function buf_set_keymap(...)
      vim.api.nvim_buf_set_keymap(bufnr, ...)
    end
    local function buf_set_option(...)
      vim.api.nvim_buf_set_option(bufnr, ...)
    end

    buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

    -- Mappings.
    local opts = { noremap = true, silent = true }
    buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
    buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
    buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
    buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
    buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
    buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
    buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
    buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
    buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
    buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
    buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
    buf_set_keymap('n', '<space>e', '<cmd>lua vim.diagnostic.open_float()<CR>', opts)
    buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
    buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
    buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.setloclist()<CR>', opts)
  end

  -- Add the server that troubles you here
  local name = 'clangd'
  -- local cmd = { 'pyright-langserver', '--stdio' } -- needed for elixirls, omnisharp, sumneko_lua
  if not name then
    print 'You have not defined a server name, please edit minimal_init.lua'
  end
  if not nvim_lsp[name].document_config.default_config.cmd and not cmd then
    print [[You have not defined a server default cmd for a server
      that requires it please edit minimal_init.lua]]
  end

  nvim_lsp[name].setup {
    -- cmd = cmd,
    on_attach = on_attach,
  }

  print [[You can find your log at $HOME/.cache/nvim/lsp.log. Please paste in a github issue under a details tag as described in the issue template.]]
end

if vim.fn.isdirectory(install_path) == 0 then
  vim.fn.system { 'git', 'clone', 'https://github.com/wbthomason/packer.nvim', install_path }
  load_plugins()
  require('packer').sync()
  vim.cmd [[autocmd User PackerComplete ++once lua load_config()]]
else
  load_plugins()
  require('packer').sync()
  _G.load_config()
end

LSP log

https://gist.github.com/JacekHoleczek/55a6e58d47b538b22abf028c7292a7d1

justinmk commented 2 years ago

This isn't a support channel. nvim-lspconfig is a set of configs. Send PRs if you find an issue.

JacekHoleczek commented 2 years ago

Sorry for using the wrong channel.

I now created: https://github.com/neovim/neovim/issues/18412

Following the discussions in the above-given thread, it seems that this is just another emanation of the known clang problems "when opening headers outside of my project directory".

The only solution is to enforce "--compile-commands-dir=/tmp/trial/src" when the clangd executable is called.

The given directory must be the "absolute path" to where the project's "compile_flags.txt" (or "compile_commands.json") resides.

Unfortunately, I do not see any foreseen option for it in the chain NVIM -> its-builtin-LSP -> nvim-lspconfig -> clangd server call.