diff options
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r-- | crates/ra_ide_api/src/impls.rs | 121 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide_api/src/navigation_target.rs | 10 |
3 files changed, 139 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs new file mode 100644 index 000000000..16a05758a --- /dev/null +++ b/crates/ra_ide_api/src/impls.rs | |||
@@ -0,0 +1,121 @@ | |||
1 | use ra_db::{SourceDatabase}; | ||
2 | use ra_syntax::{ | ||
3 | AstNode, ast, | ||
4 | algo::find_node_at_offset, | ||
5 | }; | ||
6 | use hir::{db::HirDatabase, source_binder}; | ||
7 | |||
8 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; | ||
9 | |||
10 | pub(crate) fn goto_implementation( | ||
11 | db: &RootDatabase, | ||
12 | position: FilePosition, | ||
13 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { | ||
14 | let file = db.parse(position.file_id); | ||
15 | let syntax = file.syntax(); | ||
16 | |||
17 | let krate_id = db.crate_for(position.file_id).pop()?; | ||
18 | let krate = hir::Crate { crate_id: krate_id }; | ||
19 | let module = source_binder::module_from_position(db, position)?; | ||
20 | |||
21 | let node = find_node_at_offset::<ast::NominalDef>(syntax, position.offset)?; | ||
22 | let ty = match node.kind() { | ||
23 | ast::NominalDefKind::StructDef(def) => { | ||
24 | source_binder::struct_from_module(db, module, &def).ty(db) | ||
25 | } | ||
26 | ast::NominalDefKind::EnumDef(def) => { | ||
27 | source_binder::enum_from_module(db, module, &def).ty(db) | ||
28 | } | ||
29 | }; | ||
30 | |||
31 | let impls = db.impls_in_crate(krate); | ||
32 | |||
33 | let navs = impls | ||
34 | .lookup_impl_blocks(db, &ty) | ||
35 | .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)); | ||
36 | |||
37 | Some(RangeInfo::new(node.syntax().range(), navs.collect())) | ||
38 | } | ||
39 | |||
40 | #[cfg(test)] | ||
41 | mod tests { | ||
42 | use crate::mock_analysis::analysis_and_position; | ||
43 | |||
44 | fn check_goto(fixuture: &str, expected: &[&str]) { | ||
45 | let (analysis, pos) = analysis_and_position(fixuture); | ||
46 | |||
47 | let navs = analysis.goto_implementation(pos).unwrap().unwrap().info; | ||
48 | assert_eq!(navs.len(), expected.len()); | ||
49 | navs.into_iter() | ||
50 | .enumerate() | ||
51 | .for_each(|(i, nav)| nav.assert_match(expected[i])); | ||
52 | } | ||
53 | |||
54 | #[test] | ||
55 | fn goto_implementation_works() { | ||
56 | check_goto( | ||
57 | " | ||
58 | //- /lib.rs | ||
59 | struct Foo<|>; | ||
60 | impl Foo {} | ||
61 | ", | ||
62 | &["impl IMPL_BLOCK FileId(1) [12; 23)"], | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn goto_implementation_works_multiple_blocks() { | ||
68 | check_goto( | ||
69 | " | ||
70 | //- /lib.rs | ||
71 | struct Foo<|>; | ||
72 | impl Foo {} | ||
73 | impl Foo {} | ||
74 | ", | ||
75 | &[ | ||
76 | "impl IMPL_BLOCK FileId(1) [12; 23)", | ||
77 | "impl IMPL_BLOCK FileId(1) [24; 35)", | ||
78 | ], | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | #[test] | ||
83 | fn goto_implementation_works_multiple_mods() { | ||
84 | check_goto( | ||
85 | " | ||
86 | //- /lib.rs | ||
87 | struct Foo<|>; | ||
88 | mod a { | ||
89 | impl super::Foo {} | ||
90 | } | ||
91 | mod b { | ||
92 | impl super::Foo {} | ||
93 | } | ||
94 | ", | ||
95 | &[ | ||
96 | "impl IMPL_BLOCK FileId(1) [24; 42)", | ||
97 | "impl IMPL_BLOCK FileId(1) [57; 75)", | ||
98 | ], | ||
99 | ); | ||
100 | } | ||
101 | |||
102 | #[test] | ||
103 | fn goto_implementation_works_multiple_files() { | ||
104 | check_goto( | ||
105 | " | ||
106 | //- /lib.rs | ||
107 | struct Foo<|>; | ||
108 | mod a; | ||
109 | mod b; | ||
110 | //- /a.rs | ||
111 | impl crate::Foo {} | ||
112 | //- /b.rs | ||
113 | impl crate::Foo {} | ||
114 | ", | ||
115 | &[ | ||
116 | "impl IMPL_BLOCK FileId(2) [0; 18)", | ||
117 | "impl IMPL_BLOCK FileId(3) [0; 18)", | ||
118 | ], | ||
119 | ); | ||
120 | } | ||
121 | } | ||
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 51947e4cc..9ec4fdd95 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -25,6 +25,7 @@ mod call_info; | |||
25 | mod syntax_highlighting; | 25 | mod syntax_highlighting; |
26 | mod parent_module; | 26 | mod parent_module; |
27 | mod rename; | 27 | mod rename; |
28 | mod impls; | ||
28 | 29 | ||
29 | #[cfg(test)] | 30 | #[cfg(test)] |
30 | mod marks; | 31 | mod marks; |
@@ -415,6 +416,13 @@ impl Analysis { | |||
415 | self.with_db(|db| goto_definition::goto_definition(db, position)) | 416 | self.with_db(|db| goto_definition::goto_definition(db, position)) |
416 | } | 417 | } |
417 | 418 | ||
419 | pub fn goto_implementation( | ||
420 | &self, | ||
421 | position: FilePosition, | ||
422 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { | ||
423 | self.with_db(|db| impls::goto_implementation(db, position)) | ||
424 | } | ||
425 | |||
418 | /// Finds all usages of the reference at point. | 426 | /// Finds all usages of the reference at point. |
419 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 427 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
420 | self.with_db(|db| db.find_all_refs(position)) | 428 | self.with_db(|db| db.find_all_refs(position)) |
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index d73d4afa7..5ccb5cc2e 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs | |||
@@ -147,6 +147,16 @@ impl NavigationTarget { | |||
147 | } | 147 | } |
148 | } | 148 | } |
149 | 149 | ||
150 | pub(crate) fn from_impl_block( | ||
151 | db: &RootDatabase, | ||
152 | module: hir::Module, | ||
153 | impl_block: &hir::ImplBlock, | ||
154 | ) -> NavigationTarget { | ||
155 | let (file_id, _) = module.definition_source(db); | ||
156 | let node = module.impl_source(db, impl_block.id()); | ||
157 | NavigationTarget::from_syntax(file_id, "impl".into(), None, node.syntax()) | ||
158 | } | ||
159 | |||
150 | #[cfg(test)] | 160 | #[cfg(test)] |
151 | pub(crate) fn assert_match(&self, expected: &str) { | 161 | pub(crate) fn assert_match(&self, expected: &str) { |
152 | let actual = self.debug_render(); | 162 | let actual = self.debug_render(); |