aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/import_map.rs
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-07-02 11:22:25 +0100
committerJonas Schievink <[email protected]>2020-07-02 11:43:52 +0100
commit31f5b48817a87a5875d189269e08dac56160cce2 (patch)
tree1bb4e0675d598fe662ebf4bc2b39c9514c0921e8 /crates/ra_hir_def/src/import_map.rs
parentec1d1a1b709a6eafff07077cdf75291d01cda3b6 (diff)
Record and suggest trait items via ImportMap
Diffstat (limited to 'crates/ra_hir_def/src/import_map.rs')
-rw-r--r--crates/ra_hir_def/src/import_map.rs47
1 files changed, 39 insertions, 8 deletions
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
index 68e20d06b..299fe82a8 100644
--- a/crates/ra_hir_def/src/import_map.rs
+++ b/crates/ra_hir_def/src/import_map.rs
@@ -5,14 +5,15 @@ use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc};
5use fst::{self, Streamer}; 5use fst::{self, Streamer};
6use indexmap::{map::Entry, IndexMap}; 6use indexmap::{map::Entry, IndexMap};
7use ra_db::CrateId; 7use ra_db::CrateId;
8use rustc_hash::FxHasher; 8use rustc_hash::{FxHashMap, FxHasher};
9use smallvec::SmallVec;
9 10
10use crate::{ 11use crate::{
11 db::DefDatabase, 12 db::DefDatabase,
12 item_scope::ItemInNs, 13 item_scope::ItemInNs,
13 path::{ModPath, PathKind}, 14 path::{ModPath, PathKind},
14 visibility::Visibility, 15 visibility::Visibility,
15 ModuleDefId, ModuleId, 16 AssocItemId, ModuleDefId, ModuleId, TraitId,
16}; 17};
17 18
18type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; 19type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
@@ -34,6 +35,7 @@ pub struct ImportInfo {
34/// 35///
35/// Note that all paths are relative to the containing crate's root, so the crate name still needs 36/// Note that all paths are relative to the containing crate's root, so the crate name still needs
36/// to be prepended to the `ModPath` before the path is valid. 37/// to be prepended to the `ModPath` before the path is valid.
38#[derive(Default)]
37pub struct ImportMap { 39pub struct ImportMap {
38 map: FxIndexMap<ItemInNs, ImportInfo>, 40 map: FxIndexMap<ItemInNs, ImportInfo>,
39 41
@@ -45,13 +47,17 @@ pub struct ImportMap {
45 /// the index of the first one. 47 /// the index of the first one.
46 importables: Vec<ItemInNs>, 48 importables: Vec<ItemInNs>,
47 fst: fst::Map<Vec<u8>>, 49 fst: fst::Map<Vec<u8>>,
50
51 /// Maps names of associated items to the item's ID. Only includes items whose defining trait is
52 /// exported.
53 assoc_map: FxHashMap<String, SmallVec<[AssocItemId; 1]>>,
48} 54}
49 55
50impl ImportMap { 56impl ImportMap {
51 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { 57 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
52 let _p = ra_prof::profile("import_map_query"); 58 let _p = ra_prof::profile("import_map_query");
53 let def_map = db.crate_def_map(krate); 59 let def_map = db.crate_def_map(krate);
54 let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); 60 let mut import_map = Self::default();
55 61
56 // We look only into modules that are public(ly reexported), starting with the crate root. 62 // We look only into modules that are public(ly reexported), starting with the crate root.
57 let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; 63 let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
@@ -85,7 +91,7 @@ impl ImportMap {
85 91
86 for item in per_ns.iter_items() { 92 for item in per_ns.iter_items() {
87 let path = mk_path(); 93 let path = mk_path();
88 match import_map.entry(item) { 94 match import_map.map.entry(item) {
89 Entry::Vacant(entry) => { 95 Entry::Vacant(entry) => {
90 entry.insert(ImportInfo { path, container: module }); 96 entry.insert(ImportInfo { path, container: module });
91 } 97 }
@@ -105,11 +111,16 @@ impl ImportMap {
105 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { 111 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
106 worklist.push((mod_id, mk_path())); 112 worklist.push((mod_id, mk_path()));
107 } 113 }
114
115 // If we've added a path to a trait, add the trait's methods to the method map.
116 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
117 import_map.collect_trait_methods(db, tr);
118 }
108 } 119 }
109 } 120 }
110 } 121 }
111 122
112 let mut importables = import_map.iter().collect::<Vec<_>>(); 123 let mut importables = import_map.map.iter().collect::<Vec<_>>();
113 124
114 importables.sort_by(cmp); 125 importables.sort_by(cmp);
115 126
@@ -133,10 +144,10 @@ impl ImportMap {
133 builder.insert(key, start as u64).unwrap(); 144 builder.insert(key, start as u64).unwrap();
134 } 145 }
135 146
136 let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); 147 import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
137 let importables = importables.iter().map(|(item, _)| **item).collect(); 148 import_map.importables = importables.iter().map(|(item, _)| **item).collect();
138 149
139 Arc::new(Self { map: import_map, fst, importables }) 150 Arc::new(import_map)
140 } 151 }
141 152
142 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. 153 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
@@ -147,6 +158,13 @@ impl ImportMap {
147 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { 158 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> {
148 self.map.get(&item) 159 self.map.get(&item)
149 } 160 }
161
162 fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) {
163 let data = db.trait_data(tr);
164 for (name, item) in data.items.iter() {
165 self.assoc_map.entry(name.to_string()).or_default().push(*item);
166 }
167 }
150} 168}
151 169
152impl PartialEq for ImportMap { 170impl PartialEq for ImportMap {
@@ -290,6 +308,19 @@ pub fn search_dependencies<'a>(
290 } 308 }
291 } 309 }
292 310
311 // Add all exported associated items whose names match the query (exactly).
312 for map in &import_maps {
313 if let Some(v) = map.assoc_map.get(&query.query) {
314 res.extend(v.iter().map(|&assoc| {
315 ItemInNs::Types(match assoc {
316 AssocItemId::FunctionId(it) => it.into(),
317 AssocItemId::ConstId(it) => it.into(),
318 AssocItemId::TypeAliasId(it) => it.into(),
319 })
320 }));
321 }
322 }
323
293 res 324 res
294} 325}
295 326