From 1b19a8aa5ecfc9d7115f291b97d413bd845c89b5 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Mon, 30 Dec 2019 09:12:06 -0500 Subject: Implement proposed CallHierarchy feature See: https://github.com/microsoft/vscode-languageserver-node/blob/master/protocol/src/protocol.callHierarchy.proposed.ts --- crates/ra_lsp_server/src/caps.rs | 6 +- crates/ra_lsp_server/src/conv.rs | 18 +++++ crates/ra_lsp_server/src/main_loop.rs | 3 + crates/ra_lsp_server/src/main_loop/handlers.rs | 98 +++++++++++++++++++++++++- crates/ra_lsp_server/src/req.rs | 16 +++-- 5 files changed, 129 insertions(+), 12 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index db502c200..c4711076c 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs @@ -1,8 +1,8 @@ //! Advertizes the capabilities of the LSP Server. use lsp_types::{ - CodeActionProviderCapability, CodeLensOptions, CompletionOptions, - DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, + CallHierarchyServerCapability, CodeActionProviderCapability, CodeLensOptions, + CompletionOptions, DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, @@ -56,7 +56,7 @@ pub fn server_capabilities() -> ServerCapabilities { color_provider: None, execute_command_provider: None, workspace: None, - call_hierarchy_provider: None, + call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), experimental: Default::default(), } } diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index e93d4ea33..c260b51c4 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -490,6 +490,24 @@ impl TryConvWith<&WorldSnapshot> for (FileId, RangeInfo>) } } +pub fn to_call_hierarchy_item( + file_id: FileId, + range: TextRange, + world: &WorldSnapshot, + line_index: &LineIndex, + nav: NavigationTarget, +) -> Result { + Ok(lsp_types::CallHierarchyItem { + name: nav.name().to_string(), + kind: nav.kind().conv(), + tags: None, + detail: nav.description().map(|it| it.to_string()), + uri: file_id.try_conv_with(&world)?, + range: nav.range().conv_with(&line_index), + selection_range: range.conv_with(&line_index), + }) +} + pub fn to_location( file_id: FileId, range: TextRange, diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 4336583fe..047c86a3b 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -499,6 +499,9 @@ fn on_request( .on::(handlers::handle_formatting)? .on::(handlers::handle_document_highlight)? .on::(handlers::handle_inlay_hints)? + .on::(handlers::handle_call_hierarchy_prepare)? + .on::(handlers::handle_call_hierarchy_incoming)? + .on::(handlers::handle_call_hierarchy_outgoing)? .finish(); Ok(()) } diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index c8f52eb0e..a5b6f48af 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -5,13 +5,16 @@ use std::{fmt::Write as _, io::Write as _}; use lsp_server::ErrorCode; use lsp_types::{ + CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, + CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, }; use ra_ide::{ - AssistId, FileId, FilePosition, FileRange, Query, Runnable, RunnableKind, SearchScope, + AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, + SearchScope, }; use ra_prof::profile; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; @@ -21,7 +24,10 @@ use serde_json::to_value; use crate::{ cargo_target_spec::{runnable_args, CargoTargetSpec}, - conv::{to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, TryConvWithToVec}, + conv::{ + to_call_hierarchy_item, to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, + TryConvWithToVec, + }, req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, world::WorldSnapshot, LspError, Result, @@ -936,3 +942,91 @@ pub fn handle_inlay_hints( }) .collect()) } + +pub fn handle_call_hierarchy_prepare( + world: WorldSnapshot, + params: CallHierarchyPrepareParams, +) -> Result>> { + let _p = profile("handle_call_hierarchy_prepare"); + let position = params.text_document_position_params.try_conv_with(&world)?; + let file_id = position.file_id; + + let nav_info = match world.analysis().call_hierarchy(position)? { + None => return Ok(None), + Some(it) => it, + }; + + let line_index = world.analysis().file_line_index(file_id)?; + let RangeInfo { range, info: navs } = nav_info; + let res = navs + .into_iter() + .filter(|it| it.kind() == SyntaxKind::FN_DEF) + .filter_map(|it| to_call_hierarchy_item(file_id, range, &world, &line_index, it).ok()) + .collect(); + + Ok(Some(res)) +} + +pub fn handle_call_hierarchy_incoming( + world: WorldSnapshot, + params: CallHierarchyIncomingCallsParams, +) -> Result>> { + let _p = profile("handle_call_hierarchy_incoming"); + let item = params.item; + + let doc = TextDocumentIdentifier::new(item.uri); + let frange: FileRange = (&doc, item.range).try_conv_with(&world)?; + let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; + + let call_items = match world.analysis().incoming_calls(fpos)? { + None => return Ok(None), + Some(it) => it, + }; + + let mut res = vec![]; + + for call_item in call_items.into_iter() { + let file_id = call_item.target.file_id(); + let line_index = world.analysis().file_line_index(file_id)?; + let range = call_item.target.range(); + let item = to_call_hierarchy_item(file_id, range, &world, &line_index, call_item.target)?; + res.push(CallHierarchyIncomingCall { + from: item, + from_ranges: call_item.ranges.iter().map(|it| it.conv_with(&line_index)).collect(), + }); + } + + Ok(Some(res)) +} + +pub fn handle_call_hierarchy_outgoing( + world: WorldSnapshot, + params: CallHierarchyOutgoingCallsParams, +) -> Result>> { + let _p = profile("handle_call_hierarchy_outgoing"); + let item = params.item; + + let doc = TextDocumentIdentifier::new(item.uri); + let frange: FileRange = (&doc, item.range).try_conv_with(&world)?; + let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; + + let call_items = match world.analysis().outgoing_calls(fpos)? { + None => return Ok(None), + Some(it) => it, + }; + + let mut res = vec![]; + + for call_item in call_items.into_iter() { + let file_id = call_item.target.file_id(); + let line_index = world.analysis().file_line_index(file_id)?; + let range = call_item.target.range(); + let item = to_call_hierarchy_item(file_id, range, &world, &line_index, call_item.target)?; + res.push(CallHierarchyOutgoingCall { + to: item, + from_ranges: call_item.ranges.iter().map(|it| it.conv_with(&line_index)).collect(), + }); + } + + Ok(Some(res)) +} diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index 40edaf677..8098ff31d 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs @@ -6,13 +6,15 @@ use serde::{Deserialize, Serialize}; pub use lsp_types::{ notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, - CodeLensParams, CompletionParams, CompletionResponse, DidChangeConfigurationParams, - DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions, - DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, - FileSystemWatcher, Hover, InitializeResult, MessageType, ProgressParams, ProgressParamsValue, - ProgressToken, PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams, - SelectionRange, SelectionRangeParams, ShowMessageParams, SignatureHelp, TextDocumentEdit, - TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, + CodeLensParams, CompletionParams, CompletionResponse, DiagnosticTag, + DidChangeConfigurationParams, DidChangeWatchedFilesParams, + DidChangeWatchedFilesRegistrationOptions, DocumentOnTypeFormattingParams, DocumentSymbolParams, + DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType, + PartialResultParams, ProgressParams, ProgressParamsValue, ProgressToken, + PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams, SelectionRange, + SelectionRangeParams, ServerCapabilities, ShowMessageParams, SignatureHelp, SymbolKind, + TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkDoneProgressParams, WorkspaceEdit, + WorkspaceSymbolParams, }; pub enum AnalyzerStatus {} -- cgit v1.2.3