diff options
-rw-r--r-- | crates/ra_ide_api/src/goto_type_definition.rs | 66 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 4 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 20 | ||||
-rw-r--r-- | docs/dev/lsp-features.md | 2 | ||||
-rw-r--r-- | docs/user/features.md | 12 |
7 files changed, 110 insertions, 3 deletions
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs new file mode 100644 index 000000000..de2b9d3c3 --- /dev/null +++ b/crates/ra_ide_api/src/goto_type_definition.rs | |||
@@ -0,0 +1,66 @@ | |||
1 | use ra_db::SourceDatabase; | ||
2 | use ra_syntax::{ | ||
3 | AstNode, ast, | ||
4 | algo::find_token_at_offset | ||
5 | }; | ||
6 | |||
7 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; | ||
8 | |||
9 | pub(crate) fn goto_type_definition( | ||
10 | db: &RootDatabase, | ||
11 | position: FilePosition, | ||
12 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { | ||
13 | let file = db.parse(position.file_id); | ||
14 | |||
15 | let node = find_token_at_offset(file.syntax(), position.offset).find_map(|token| { | ||
16 | token | ||
17 | .parent() | ||
18 | .ancestors() | ||
19 | .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some()) | ||
20 | })?; | ||
21 | |||
22 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, node, None); | ||
23 | |||
24 | let ty: hir::Ty = if let Some(ty) = ast::Expr::cast(node).and_then(|e| analyzer.type_of(db, e)) | ||
25 | { | ||
26 | ty | ||
27 | } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| analyzer.type_of_pat(db, p)) { | ||
28 | ty | ||
29 | } else { | ||
30 | return None; | ||
31 | }; | ||
32 | |||
33 | let (adt_def, _) = ty.as_adt()?; | ||
34 | let nav = NavigationTarget::from_adt_def(db, adt_def); | ||
35 | |||
36 | Some(RangeInfo::new(node.range(), vec![nav])) | ||
37 | } | ||
38 | |||
39 | #[cfg(test)] | ||
40 | mod tests { | ||
41 | use crate::mock_analysis::analysis_and_position; | ||
42 | |||
43 | fn check_goto(fixture: &str, expected: &str) { | ||
44 | let (analysis, pos) = analysis_and_position(fixture); | ||
45 | |||
46 | let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info; | ||
47 | assert_eq!(navs.len(), 1); | ||
48 | let nav = navs.pop().unwrap(); | ||
49 | nav.assert_match(expected); | ||
50 | } | ||
51 | |||
52 | #[test] | ||
53 | fn goto_type_definition_works_simple() { | ||
54 | check_goto( | ||
55 | " | ||
56 | //- /lib.rs | ||
57 | struct Foo; | ||
58 | fn foo() { | ||
59 | let f: Foo; | ||
60 | f<|> | ||
61 | } | ||
62 | ", | ||
63 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
64 | ); | ||
65 | } | ||
66 | } | ||
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index d25795adc..d4be8bd6c 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -19,6 +19,7 @@ mod status; | |||
19 | mod completion; | 19 | mod completion; |
20 | mod runnables; | 20 | mod runnables; |
21 | mod goto_definition; | 21 | mod goto_definition; |
22 | mod goto_type_definition; | ||
22 | mod extend_selection; | 23 | mod extend_selection; |
23 | mod hover; | 24 | mod hover; |
24 | mod call_info; | 25 | mod call_info; |
@@ -416,6 +417,13 @@ impl Analysis { | |||
416 | self.with_db(|db| impls::goto_implementation(db, position)) | 417 | self.with_db(|db| impls::goto_implementation(db, position)) |
417 | } | 418 | } |
418 | 419 | ||
420 | pub fn goto_type_definition( | ||
421 | &self, | ||
422 | position: FilePosition, | ||
423 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { | ||
424 | self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) | ||
425 | } | ||
426 | |||
419 | /// Finds all usages of the reference at point. | 427 | /// Finds all usages of the reference at point. |
420 | pub fn find_all_refs( | 428 | pub fn find_all_refs( |
421 | &self, | 429 | &self, |
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index f6d2b75e7..9095bee89 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -2,7 +2,7 @@ use lsp_types::{ | |||
2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, | 2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, |
3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, | 3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, |
4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
5 | TextDocumentSyncOptions, ImplementationProviderCapability, GenericCapability, | 5 | TextDocumentSyncOptions, ImplementationProviderCapability, GenericCapability, TypeDefinitionProviderCapability |
6 | }; | 6 | }; |
7 | 7 | ||
8 | pub fn server_capabilities() -> ServerCapabilities { | 8 | pub fn server_capabilities() -> ServerCapabilities { |
@@ -23,7 +23,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
23 | trigger_characters: Some(vec!["(".to_string(), ",".to_string(), ")".to_string()]), | 23 | trigger_characters: Some(vec!["(".to_string(), ",".to_string(), ")".to_string()]), |
24 | }), | 24 | }), |
25 | definition_provider: Some(true), | 25 | definition_provider: Some(true), |
26 | type_definition_provider: None, | 26 | type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), |
27 | implementation_provider: Some(ImplementationProviderCapability::Simple(true)), | 27 | implementation_provider: Some(ImplementationProviderCapability::Simple(true)), |
28 | references_provider: Some(true), | 28 | references_provider: Some(true), |
29 | document_highlight_provider: Some(true), | 29 | document_highlight_provider: Some(true), |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index dc1f8f3f7..87b4e3ac2 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -306,6 +306,7 @@ fn on_request( | |||
306 | .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? | 306 | .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? |
307 | .on::<req::GotoDefinition>(handlers::handle_goto_definition)? | 307 | .on::<req::GotoDefinition>(handlers::handle_goto_definition)? |
308 | .on::<req::GotoImplementation>(handlers::handle_goto_implementation)? | 308 | .on::<req::GotoImplementation>(handlers::handle_goto_implementation)? |
309 | .on::<req::GotoTypeDefinition>(handlers::handle_goto_type_definition)? | ||
309 | .on::<req::ParentModule>(handlers::handle_parent_module)? | 310 | .on::<req::ParentModule>(handlers::handle_parent_module)? |
310 | .on::<req::Runnables>(handlers::handle_runnables)? | 311 | .on::<req::Runnables>(handlers::handle_runnables)? |
311 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? | 312 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 530081494..23802e5e1 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -288,6 +288,26 @@ pub fn handle_goto_implementation( | |||
288 | Ok(Some(req::GotoDefinitionResponse::Link(res))) | 288 | Ok(Some(req::GotoDefinitionResponse::Link(res))) |
289 | } | 289 | } |
290 | 290 | ||
291 | pub fn handle_goto_type_definition( | ||
292 | world: ServerWorld, | ||
293 | params: req::TextDocumentPositionParams, | ||
294 | ) -> Result<Option<req::GotoTypeDefinitionResponse>> { | ||
295 | let position = params.try_conv_with(&world)?; | ||
296 | let line_index = world.analysis().file_line_index(position.file_id); | ||
297 | let nav_info = match world.analysis().goto_type_definition(position)? { | ||
298 | None => return Ok(None), | ||
299 | Some(it) => it, | ||
300 | }; | ||
301 | let nav_range = nav_info.range; | ||
302 | let res = nav_info | ||
303 | .info | ||
304 | .into_iter() | ||
305 | .map(|nav| RangeInfo::new(nav_range, nav)) | ||
306 | .map(|nav| to_location_link(&nav, &world, &line_index)) | ||
307 | .collect::<Result<Vec<_>>>()?; | ||
308 | Ok(Some(req::GotoDefinitionResponse::Link(res))) | ||
309 | } | ||
310 | |||
291 | pub fn handle_parent_module( | 311 | pub fn handle_parent_module( |
292 | world: ServerWorld, | 312 | world: ServerWorld, |
293 | params: req::TextDocumentPositionParams, | 313 | params: req::TextDocumentPositionParams, |
diff --git a/docs/dev/lsp-features.md b/docs/dev/lsp-features.md index 57015293c..28bae59bb 100644 --- a/docs/dev/lsp-features.md +++ b/docs/dev/lsp-features.md | |||
@@ -46,7 +46,7 @@ This list documents LSP features, supported by rust-analyzer. | |||
46 | - trigger characters: `(`, `,`, `)` | 46 | - trigger characters: `(`, `,`, `)` |
47 | - [ ] [textDocument/declaration](https://microsoft.github.io/language-server-protocol/specification#textDocument_declaration) | 47 | - [ ] [textDocument/declaration](https://microsoft.github.io/language-server-protocol/specification#textDocument_declaration) |
48 | - [x] [textDocument/definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) | 48 | - [x] [textDocument/definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) |
49 | - [ ] [textDocument/typeDefinition](https://microsoft.github.io/language-server-protocol/specification#textDocument_typeDefinition) | 49 | - [x] [textDocument/typeDefinition](https://microsoft.github.io/language-server-protocol/specification#textDocument_typeDefinition) |
50 | - [x] [textDocument/implementation](https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation) | 50 | - [x] [textDocument/implementation](https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation) |
51 | - [x] [textDocument/references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references) | 51 | - [x] [textDocument/references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references) |
52 | - [x] [textDocument/documentHighlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight) | 52 | - [x] [textDocument/documentHighlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight) |
diff --git a/docs/user/features.md b/docs/user/features.md index b44a3fce1..cbfc491b2 100644 --- a/docs/user/features.md +++ b/docs/user/features.md | |||
@@ -42,6 +42,18 @@ is a relatively new feature of LSP: | |||
42 | https://github.com/Microsoft/language-server-protocol/issues/613, check your | 42 | https://github.com/Microsoft/language-server-protocol/issues/613, check your |
43 | editor's LSP library to see if this feature is supported. | 43 | editor's LSP library to see if this feature is supported. |
44 | 44 | ||
45 | ### Go to Definition | ||
46 | |||
47 | Navigates to the definition of an identifier. | ||
48 | |||
49 | ### Go to Implementation | ||
50 | |||
51 | Navigates to the impl block of structs, enums or traits. Also implemented as a code lens. | ||
52 | |||
53 | ### Go to Type Defintion | ||
54 | |||
55 | Navigates to the type of an identifier. | ||
56 | |||
45 | ### Commands <kbd>ctrl+shift+p</kbd> | 57 | ### Commands <kbd>ctrl+shift+p</kbd> |
46 | 58 | ||
47 | #### Run | 59 | #### Run |