aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/impls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/impls.rs')
-rw-r--r--crates/ra_ide_api/src/impls.rs84
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
34fn 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
59fn 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}