aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs66
-rw-r--r--crates/ra_ide_api/src/lib.rs8
-rw-r--r--crates/ra_lsp_server/src/caps.rs4
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs20
5 files changed, 97 insertions, 2 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 @@
1use ra_db::SourceDatabase;
2use ra_syntax::{
3 AstNode, ast,
4 algo::find_token_at_offset
5};
6
7use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
8
9pub(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)]
40mod 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;
19mod completion; 19mod completion;
20mod runnables; 20mod runnables;
21mod goto_definition; 21mod goto_definition;
22mod goto_type_definition;
22mod extend_selection; 23mod extend_selection;
23mod hover; 24mod hover;
24mod call_info; 25mod 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
8pub fn server_capabilities() -> ServerCapabilities { 8pub 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
291pub 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
291pub fn handle_parent_module( 311pub fn handle_parent_module(
292 world: ServerWorld, 312 world: ServerWorld,
293 params: req::TextDocumentPositionParams, 313 params: req::TextDocumentPositionParams,