diff options
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r-- | crates/ra_ide_api/src/impls.rs | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs index 469d56d63..91fa41f1f 100644 --- a/crates/ra_ide_api/src/impls.rs +++ b/crates/ra_ide_api/src/impls.rs | |||
@@ -15,9 +15,27 @@ pub(crate) fn goto_implementation( | |||
15 | let syntax = file.syntax(); | 15 | let syntax = file.syntax(); |
16 | 16 | ||
17 | let module = source_binder::module_from_position(db, position)?; | 17 | let module = source_binder::module_from_position(db, position)?; |
18 | let krate = module.krate(db)?; | ||
19 | 18 | ||
20 | let node = find_node_at_offset::<ast::NominalDef>(syntax, position.offset)?; | 19 | if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(syntax, position.offset) { |
20 | return Some(RangeInfo::new( | ||
21 | nominal_def.syntax().range(), | ||
22 | impls_for_def(db, nominal_def, module)?, | ||
23 | )); | ||
24 | } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(syntax, position.offset) { | ||
25 | return Some(RangeInfo::new( | ||
26 | trait_def.syntax().range(), | ||
27 | impls_for_trait(db, trait_def, module)?, | ||
28 | )); | ||
29 | } | ||
30 | |||
31 | None | ||
32 | } | ||
33 | |||
34 | fn impls_for_def( | ||
35 | db: &RootDatabase, | ||
36 | node: &ast::NominalDef, | ||
37 | module: hir::Module, | ||
38 | ) -> Option<Vec<NavigationTarget>> { | ||
21 | let ty = match node.kind() { | 39 | let ty = match node.kind() { |
22 | ast::NominalDefKind::StructDef(def) => { | 40 | ast::NominalDefKind::StructDef(def) => { |
23 | source_binder::struct_from_module(db, module, &def).ty(db) | 41 | source_binder::struct_from_module(db, module, &def).ty(db) |
@@ -27,13 +45,33 @@ pub(crate) fn goto_implementation( | |||
27 | } | 45 | } |
28 | }; | 46 | }; |
29 | 47 | ||
48 | let krate = module.krate(db)?; | ||
30 | let impls = db.impls_in_crate(krate); | 49 | let impls = db.impls_in_crate(krate); |
31 | 50 | ||
32 | let navs = impls | 51 | Some( |
33 | .lookup_impl_blocks(db, &ty) | 52 | impls |
34 | .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)); | 53 | .lookup_impl_blocks(db, &ty) |
54 | .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)) | ||
55 | .collect(), | ||
56 | ) | ||
57 | } | ||
58 | |||
59 | fn impls_for_trait( | ||
60 | db: &RootDatabase, | ||
61 | node: &ast::TraitDef, | ||
62 | module: hir::Module, | ||
63 | ) -> Option<Vec<NavigationTarget>> { | ||
64 | let tr = source_binder::trait_from_module(db, module, node); | ||
35 | 65 | ||
36 | Some(RangeInfo::new(node.syntax().range(), navs.collect())) | 66 | let krate = module.krate(db)?; |
67 | let impls = db.impls_in_crate(krate); | ||
68 | |||
69 | Some( | ||
70 | impls | ||
71 | .lookup_impl_blocks_for_trait(db, &tr) | ||
72 | .map(|(module, imp)| NavigationTarget::from_impl_block(db, module, &imp)) | ||
73 | .collect(), | ||
74 | ) | ||
37 | } | 75 | } |
38 | 76 | ||
39 | #[cfg(test)] | 77 | #[cfg(test)] |
@@ -117,4 +155,38 @@ mod tests { | |||
117 | ], | 155 | ], |
118 | ); | 156 | ); |
119 | } | 157 | } |
158 | |||
159 | #[test] | ||
160 | fn goto_implementation_for_trait() { | ||
161 | check_goto( | ||
162 | " | ||
163 | //- /lib.rs | ||
164 | trait T<|> {} | ||
165 | struct Foo; | ||
166 | impl T for Foo {} | ||
167 | ", | ||
168 | &["impl IMPL_BLOCK FileId(1) [23; 40)"], | ||
169 | ); | ||
170 | } | ||
171 | |||
172 | #[test] | ||
173 | fn goto_implementation_for_trait_multiple_files() { | ||
174 | check_goto( | ||
175 | " | ||
176 | //- /lib.rs | ||
177 | trait T<|> {}; | ||
178 | struct Foo; | ||
179 | mod a; | ||
180 | mod b; | ||
181 | //- /a.rs | ||
182 | impl crate::T for crate::Foo {} | ||
183 | //- /b.rs | ||
184 | impl crate::T for crate::Foo {} | ||
185 | ", | ||
186 | &[ | ||
187 | "impl IMPL_BLOCK FileId(2) [0; 31)", | ||
188 | "impl IMPL_BLOCK FileId(3) [0; 31)", | ||
189 | ], | ||
190 | ); | ||
191 | } | ||
120 | } | 192 | } |