lsp: Add support for call hierarchies (#12556)

* LSP: Add support for call hierarchies

* LSP: Add support for call hierarchies

* LSP: Add support for call hierarchies

* LSP: Jump to call location

Jump to the call site instead of jumping to the definition of the
caller/callee.

* LSP: add tests for the call hierarchy callbacks

* Fix linting error

Co-authored-by: Cédric Barreteau <>
This commit is contained in:
cbarrete
2020-07-18 21:10:09 +02:00
committed by GitHub
parent a02a267f8a
commit 08efa7037e
6 changed files with 217 additions and 0 deletions

View File

@@ -511,6 +511,7 @@ function lsp.start_client(config)
or (not client.resolved_capabilities.type_definition and method == 'textDocument/typeDefinition')
or (not client.resolved_capabilities.document_symbol and method == 'textDocument/documentSymbol')
or (not client.resolved_capabilities.workspace_symbol and method == 'textDocument/workspaceSymbol')
or (not client.resolved_capabilities.call_hierarchy and method == 'textDocument/prepareCallHierarchy')
then
callback(unsupported_method(method), method, nil, client_id, bufnr)
return

View File

@@ -143,6 +143,38 @@ function M.document_symbol()
request('textDocument/documentSymbol', params)
end
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then return end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
local items = {}
for i, item in ipairs(call_hierarchy_items) do
local entry = item.detail or item.name
table.insert(items, string.format("%d. %s", i, entry))
end
local choice = vim.fn.inputlist(items)
if choice < 1 or choice > #items then
return
end
return choice
end
function M.incoming_calls()
local params = util.make_position_params()
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
local call_hierarchy_item = pick_call_hierarchy_item(result)
vim.lsp.buf_request(0, 'callHierarchy/incomingCalls', { item = call_hierarchy_item })
end)
end
function M.outgoing_calls()
local params = util.make_position_params()
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
local call_hierarchy_item = pick_call_hierarchy_item(result)
vim.lsp.buf_request(0, 'callHierarchy/outgoingCalls', { item = call_hierarchy_item })
end)
end
--- Lists all symbols in the current workspace in the quickfix window.
---

View File

@@ -214,6 +214,33 @@ M['textDocument/documentHighlight'] = function(_, _, result, _)
util.buf_highlight_references(bufnr, result)
end
-- direction is "from" for incoming calls and "to" for outgoing calls
local make_call_hierarchy_callback = function(direction)
-- result is a CallHierarchy{Incoming,Outgoing}Call[]
return function(_, _, result)
if not result then return end
local items = {}
for _, call_hierarchy_call in pairs(result) do
local call_hierarchy_item = call_hierarchy_call[direction]
for _, range in pairs(call_hierarchy_call.fromRanges) do
table.insert(items, {
filename = assert(vim.uri_to_fname(call_hierarchy_item.uri)),
text = call_hierarchy_item.name,
lnum = range.start.line + 1,
col = range.start.character + 1,
})
end
end
util.set_qflist(items)
api.nvim_command("copen")
api.nvim_command("wincmd p")
end
end
M['callHierarchy/incomingCalls'] = make_call_hierarchy_callback('from')
M['callHierarchy/outgoingCalls'] = make_call_hierarchy_callback('to')
M['window/logMessage'] = function(_, _, result, client_id)
local message_type = result.type
local message = result.message

View File

@@ -713,6 +713,9 @@ function protocol.make_client_capabilities()
};
applyEdit = true;
};
callHierarchy = {
dynamicRegistration = false;
};
experimental = nil;
}
end
@@ -912,6 +915,7 @@ function protocol.resolve_capabilities(server_capabilities)
general_properties.workspace_symbol = server_capabilities.workspaceSymbolProvider or false
general_properties.document_formatting = server_capabilities.documentFormattingProvider or false
general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider or false
general_properties.call_hierarchy = server_capabilities.callHierarchyProvider or false
if server_capabilities.codeActionProvider == nil then
general_properties.code_action = false