aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/source_binder.rs15
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs67
-rw-r--r--crates/ra_ide_api/src/impls.rs84
3 files changed, 140 insertions, 26 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index d1eaccf23..a1b94ed9c 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -14,7 +14,7 @@ use ra_syntax::{
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, ModuleDef, Struct, Enum, 16 HirDatabase, Function, ModuleDef, Struct, Enum,
17 AsName, Module, HirFileId, Crate, 17 AsName, Module, HirFileId, Crate, Trait,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::{LocationCtx, SourceFileItemId},
19}; 19};
20 20
@@ -151,6 +151,19 @@ pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::E
151 } 151 }
152} 152}
153 153
154pub fn trait_from_module(
155 db: &impl HirDatabase,
156 module: Module,
157 trait_def: &ast::TraitDef,
158) -> Trait {
159 let (file_id, _) = module.definition_source(db);
160 let file_id = file_id.into();
161 let ctx = LocationCtx::new(db, module, file_id);
162 Trait {
163 id: ctx.to_def(trait_def),
164 }
165}
166
154pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> { 167pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> {
155 let module = match module_from_file_id(db, file_id) { 168 let module = match module_from_file_id(db, file_id) {
156 Some(it) => it, 169 Some(it) => it,
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 37bc3f38c..e857d6856 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,17 +7,18 @@ use std::sync::Arc;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, 10 HirDatabase, module_tree::ModuleId, Module, ModuleDef, Crate, Name, Function, Trait,
11 ids::TraitId,
11 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
12 generics::GenericParams, 13 generics::GenericParams,
13 ty::{AdtDef, Ty} 14 ty::{AdtDef, Ty},
15 type_ref::TypeRef,
14}; 16};
15 17
16/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
17#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
18pub enum TyFingerprint { 20pub enum TyFingerprint {
19 Adt(AdtDef), 21 Adt(AdtDef), // we'll also want to index impls for primitive types etc.
20 // we'll also want to index impls for primitive types etc.
21} 22}
22 23
23impl TyFingerprint { 24impl TyFingerprint {
@@ -37,6 +38,7 @@ pub struct CrateImplBlocks {
37 /// To make sense of the ModuleIds, we need the source root. 38 /// To make sense of the ModuleIds, we need the source root.
38 krate: Crate, 39 krate: Crate,
39 impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>,
41 impls_by_trait: FxHashMap<TraitId, Vec<(ModuleId, ImplId)>>,
40} 42}
41 43
42impl CrateImplBlocks { 44impl CrateImplBlocks {
@@ -60,27 +62,53 @@ impl CrateImplBlocks {
60 }) 62 })
61 } 63 }
62 64
65 pub fn lookup_impl_blocks_for_trait<'a>(
66 &'a self,
67 db: &'a impl HirDatabase,
68 tr: &Trait,
69 ) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
70 let id = tr.id;
71 self.impls_by_trait
72 .get(&id)
73 .into_iter()
74 .flat_map(|i| i.iter())
75 .map(move |(module_id, impl_id)| {
76 let module = Module {
77 krate: self.krate,
78 module_id: *module_id,
79 };
80 let module_impl_blocks = db.impls_in_module(module);
81 (module, ImplBlock::from_id(module_impl_blocks, *impl_id))
82 })
83 }
84
63 fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) { 85 fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
64 let module_impl_blocks = db.impls_in_module(module.clone()); 86 let module_impl_blocks = db.impls_in_module(module.clone());
65 87
66 for (impl_id, impl_data) in module_impl_blocks.impls.iter() { 88 for (impl_id, impl_data) in module_impl_blocks.impls.iter() {
67 let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id); 89 let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id);
90 // TODO provide generics of impl
91 let generics = GenericParams::default();
92 let target_ty = Ty::from_hir(
93 db,
94 &module,
95 Some(&impl_block),
96 &generics,
97 impl_data.target_type(),
98 );
99
100 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
101 self.impls
102 .entry(target_ty_fp)
103 .or_insert_with(Vec::new)
104 .push((module.module_id, impl_id));
105 }
68 106
69 if let Some(_target_trait) = impl_data.target_trait() { 107 if let Some(TypeRef::Path(path)) = impl_data.target_trait() {
70 // ignore for now 108 let perns = module.resolve_path(db, path);
71 } else { 109 if let Some(ModuleDef::Trait(tr)) = perns.take_types() {
72 // TODO provide generics of impl 110 self.impls_by_trait
73 let generics = GenericParams::default(); 111 .entry(tr.id)
74 let target_ty = Ty::from_hir(
75 db,
76 &module,
77 Some(&impl_block),
78 &generics,
79 impl_data.target_type(),
80 );
81 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
82 self.impls
83 .entry(target_ty_fp)
84 .or_insert_with(Vec::new) 112 .or_insert_with(Vec::new)
85 .push((module.module_id, impl_id)); 113 .push((module.module_id, impl_id));
86 } 114 }
@@ -99,6 +127,7 @@ impl CrateImplBlocks {
99 let mut crate_impl_blocks = CrateImplBlocks { 127 let mut crate_impl_blocks = CrateImplBlocks {
100 krate: krate.clone(), 128 krate: krate.clone(),
101 impls: FxHashMap::default(), 129 impls: FxHashMap::default(),
130 impls_by_trait: FxHashMap::default(),
102 }; 131 };
103 if let Some(module) = krate.root_module(db) { 132 if let Some(module) = krate.root_module(db) {
104 crate_impl_blocks.collect_recursive(db, &module); 133 crate_impl_blocks.collect_recursive(db, &module);
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}