aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2021-02-24 23:06:31 +0000
committerKirill Bulatov <[email protected]>2021-03-08 21:59:18 +0000
commit582cee2cdf5355b681f14bbb33bd5c431c284d87 (patch)
tree47d25e9c057759b1aa334abf3f584f1d0317d941 /crates/ide_db
parent309421c117fc20e58b9f30fb28a01a89f50b0086 (diff)
Return more data about located imports
Diffstat (limited to 'crates/ide_db')
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs179
-rw-r--r--crates/ide_db/src/imports_locator.rs11
2 files changed, 114 insertions, 76 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index dc3b92a64..d8bf61aaa 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -117,6 +117,42 @@ impl ImportAssets {
117 } 117 }
118} 118}
119 119
120#[derive(Debug, Clone, PartialEq, Eq, Hash)]
121pub struct LocatedImport {
122 import_path: ModPath,
123 item_to_import: ItemInNs,
124 import_display_override: Option<(ModPath, ItemInNs)>,
125}
126
127impl LocatedImport {
128 pub fn new(
129 import_path: ModPath,
130 item_to_import: ItemInNs,
131 import_display_override: Option<(ModPath, ItemInNs)>,
132 ) -> Self {
133 Self { import_path, item_to_import, import_display_override }
134 }
135
136 pub fn display_path(&self) -> &ModPath {
137 self.import_display_override
138 .as_ref()
139 .map(|(mod_path, _)| mod_path)
140 .unwrap_or(&self.import_path)
141 }
142
143 pub fn import_path(&self) -> &ModPath {
144 &self.import_path
145 }
146
147 pub fn item_to_display(&self) -> ItemInNs {
148 self.import_display_override.as_ref().map(|&(_, item)| item).unwrap_or(self.item_to_import)
149 }
150
151 pub fn item_to_import(&self) -> ItemInNs {
152 self.item_to_import
153 }
154}
155
120impl ImportAssets { 156impl ImportAssets {
121 pub fn import_candidate(&self) -> &ImportCandidate { 157 pub fn import_candidate(&self) -> &ImportCandidate {
122 &self.import_candidate 158 &self.import_candidate
@@ -134,16 +170,13 @@ impl ImportAssets {
134 &self, 170 &self,
135 sema: &Semantics<RootDatabase>, 171 sema: &Semantics<RootDatabase>,
136 prefix_kind: PrefixKind, 172 prefix_kind: PrefixKind,
137 ) -> Vec<(hir::ModPath, hir::ItemInNs)> { 173 ) -> Vec<LocatedImport> {
138 let _p = profile::span("import_assets::search_for_imports"); 174 let _p = profile::span("import_assets::search_for_imports");
139 self.search_for(sema, Some(prefix_kind)) 175 self.search_for(sema, Some(prefix_kind))
140 } 176 }
141 177
142 /// This may return non-absolute paths if a part of the returned path is already imported into scope. 178 /// This may return non-absolute paths if a part of the returned path is already imported into scope.
143 pub fn search_for_relative_paths( 179 pub fn search_for_relative_paths(&self, sema: &Semantics<RootDatabase>) -> Vec<LocatedImport> {
144 &self,
145 sema: &Semantics<RootDatabase>,
146 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
147 let _p = profile::span("import_assets::search_for_relative_paths"); 180 let _p = profile::span("import_assets::search_for_relative_paths");
148 self.search_for(sema, None) 181 self.search_for(sema, None)
149 } 182 }
@@ -152,7 +185,7 @@ impl ImportAssets {
152 &self, 185 &self,
153 sema: &Semantics<RootDatabase>, 186 sema: &Semantics<RootDatabase>,
154 prefixed: Option<hir::PrefixKind>, 187 prefixed: Option<hir::PrefixKind>,
155 ) -> Vec<(hir::ModPath, hir::ItemInNs)> { 188 ) -> Vec<LocatedImport> {
156 let current_crate = self.module_with_candidate.krate(); 189 let current_crate = self.module_with_candidate.krate();
157 190
158 let imports_for_candidate_name = match self.name_to_import() { 191 let imports_for_candidate_name = match self.name_to_import() {
@@ -181,61 +214,53 @@ impl ImportAssets {
181 } 214 }
182 }; 215 };
183 216
184 let mut res = self 217 self.applicable_defs(sema.db, prefixed, imports_for_candidate_name)
185 .applicable_defs(sema, prefixed, imports_for_candidate_name) 218 .into_iter()
186 .filter(|(use_path, _)| use_path.len() > 1) 219 .filter(|import| import.import_path().len() > 1)
187 .collect::<Vec<_>>(); 220 .collect()
188 res.sort_by_cached_key(|(path, _)| path.clone());
189 res
190 } 221 }
191 222
192 fn applicable_defs<'a>( 223 fn applicable_defs(
193 &'a self, 224 &self,
194 sema: &'a Semantics<RootDatabase>, 225 db: &RootDatabase,
195 prefixed: Option<hir::PrefixKind>, 226 prefixed: Option<hir::PrefixKind>,
196 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, 227 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
197 ) -> Box<dyn Iterator<Item = (ModPath, ItemInNs)> + 'a> { 228 ) -> FxHashSet<LocatedImport> {
198 let current_crate = self.module_with_candidate.krate(); 229 let current_crate = self.module_with_candidate.krate();
199 let db = sema.db; 230
231 let import_path_locator =
232 |item| get_mod_path(db, item, &self.module_with_candidate, prefixed);
200 233
201 match &self.import_candidate { 234 match &self.import_candidate {
202 ImportCandidate::Path(path_candidate) => Box::new( 235 ImportCandidate::Path(path_candidate) => {
203 path_applicable_items( 236 path_applicable_imports(db, path_candidate, import_path_locator, unfiltered_defs)
204 db, 237 }
205 path_candidate, 238 ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items(
206 &self.module_with_candidate, 239 db,
207 prefixed, 240 current_crate,
208 unfiltered_defs, 241 trait_candidate,
209 ) 242 true,
210 .into_iter(), 243 import_path_locator,
211 ), 244 unfiltered_defs,
212 ImportCandidate::TraitAssocItem(trait_candidate) => Box::new(
213 trait_applicable_defs(db, current_crate, trait_candidate, true, unfiltered_defs)
214 .into_iter()
215 .filter_map(move |item_to_search| {
216 get_mod_path(db, item_to_search, &self.module_with_candidate, prefixed)
217 .zip(Some(item_to_search))
218 }),
219 ), 245 ),
220 ImportCandidate::TraitMethod(trait_candidate) => Box::new( 246 ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
221 trait_applicable_defs(db, current_crate, trait_candidate, false, unfiltered_defs) 247 db,
222 .into_iter() 248 current_crate,
223 .filter_map(move |item_to_search| { 249 trait_candidate,
224 get_mod_path(db, item_to_search, &self.module_with_candidate, prefixed) 250 false,
225 .zip(Some(item_to_search)) 251 import_path_locator,
226 }), 252 unfiltered_defs,
227 ), 253 ),
228 } 254 }
229 } 255 }
230} 256}
231 257
232fn path_applicable_items<'a>( 258fn path_applicable_imports(
233 db: &'a RootDatabase, 259 db: &RootDatabase,
234 path_candidate: &'a PathImportCandidate, 260 path_candidate: &PathImportCandidate,
235 module_with_candidate: &hir::Module, 261 import_path_locator: impl Fn(ItemInNs) -> Option<ModPath>,
236 prefixed: Option<hir::PrefixKind>, 262 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
237 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, 263) -> FxHashSet<LocatedImport> {
238) -> FxHashSet<(ModPath, ItemInNs)> {
239 let applicable_items = unfiltered_defs 264 let applicable_items = unfiltered_defs
240 .filter_map(|def| { 265 .filter_map(|def| {
241 let (assoc_original, candidate) = match def { 266 let (assoc_original, candidate) = match def {
@@ -256,14 +281,15 @@ fn path_applicable_items<'a>(
256 Some((assoc_original, candidate)) 281 Some((assoc_original, candidate))
257 }) 282 })
258 .filter_map(|(assoc_original, candidate)| { 283 .filter_map(|(assoc_original, candidate)| {
259 get_mod_path(db, candidate, module_with_candidate, prefixed) 284 import_path_locator(candidate).zip(Some((assoc_original, candidate)))
260 .zip(Some((assoc_original, candidate)))
261 }); 285 });
262 286
263 let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { 287 let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier {
264 Qualifier::Absent => { 288 Qualifier::Absent => {
265 return applicable_items 289 return applicable_items
266 .map(|(candidate_path, (_, candidate))| (candidate_path, candidate)) 290 .map(|(candidate_path, (_, candidate))| {
291 LocatedImport::new(candidate_path, candidate, None)
292 })
267 .collect(); 293 .collect();
268 } 294 }
269 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier), 295 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier),
@@ -283,19 +309,22 @@ fn path_applicable_items<'a>(
283 .filter_map(|(candidate_path, (assoc_original, candidate))| { 309 .filter_map(|(candidate_path, (assoc_original, candidate))| {
284 if let Some(assoc_original) = assoc_original { 310 if let Some(assoc_original) = assoc_original {
285 if item_name(db, candidate)?.to_string() == unresolved_first_segment_string { 311 if item_name(db, candidate)?.to_string() == unresolved_first_segment_string {
286 return Some((candidate_path, ItemInNs::from(assoc_original))); 312 return Some(LocatedImport::new(
313 candidate_path.clone(),
314 ItemInNs::from(assoc_original),
315 Some((candidate_path, candidate)),
316 ));
287 } 317 }
288 } 318 }
289 319
290 let matching_module = 320 let matching_module =
291 module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; 321 module_with_matching_name(db, &unresolved_first_segment_string, candidate)?;
292 let path = get_mod_path( 322 let item = ItemInNs::from(ModuleDef::from(matching_module));
293 db, 323 Some(LocatedImport::new(
294 ItemInNs::from(ModuleDef::from(matching_module)), 324 import_path_locator(item)?,
295 module_with_candidate, 325 item,
296 prefixed, 326 Some((candidate_path, candidate)),
297 )?; 327 ))
298 Some((path, candidate))
299 }) 328 })
300 .collect() 329 .collect()
301} 330}
@@ -336,13 +365,14 @@ fn module_with_matching_name(
336 None 365 None
337} 366}
338 367
339fn trait_applicable_defs<'a>( 368fn trait_applicable_items(
340 db: &'a RootDatabase, 369 db: &RootDatabase,
341 current_crate: Crate, 370 current_crate: Crate,
342 trait_candidate: &TraitImportCandidate, 371 trait_candidate: &TraitImportCandidate,
343 trait_assoc_item: bool, 372 trait_assoc_item: bool,
344 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, 373 import_path_locator: impl Fn(ItemInNs) -> Option<ModPath>,
345) -> FxHashSet<ItemInNs> { 374 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
375) -> FxHashSet<LocatedImport> {
346 let mut required_assoc_items = FxHashSet::default(); 376 let mut required_assoc_items = FxHashSet::default();
347 377
348 let trait_candidates = unfiltered_defs 378 let trait_candidates = unfiltered_defs
@@ -357,7 +387,7 @@ fn trait_applicable_defs<'a>(
357 }) 387 })
358 .collect(); 388 .collect();
359 389
360 let mut applicable_traits = FxHashSet::default(); 390 let mut located_imports = FxHashSet::default();
361 391
362 if trait_assoc_item { 392 if trait_assoc_item {
363 trait_candidate.receiver_ty.iterate_path_candidates( 393 trait_candidate.receiver_ty.iterate_path_candidates(
@@ -372,8 +402,13 @@ fn trait_applicable_defs<'a>(
372 return None; 402 return None;
373 } 403 }
374 } 404 }
375 applicable_traits 405
376 .insert(ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?))); 406 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
407 located_imports.insert(LocatedImport::new(
408 import_path_locator(item)?,
409 item,
410 None,
411 ));
377 } 412 }
378 None::<()> 413 None::<()>
379 }, 414 },
@@ -387,15 +422,19 @@ fn trait_applicable_defs<'a>(
387 |_, function| { 422 |_, function| {
388 let assoc = function.as_assoc_item(db)?; 423 let assoc = function.as_assoc_item(db)?;
389 if required_assoc_items.contains(&assoc) { 424 if required_assoc_items.contains(&assoc) {
390 applicable_traits 425 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
391 .insert(ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?))); 426 located_imports.insert(LocatedImport::new(
427 import_path_locator(item)?,
428 item,
429 None,
430 ));
392 } 431 }
393 None::<()> 432 None::<()>
394 }, 433 },
395 ) 434 )
396 }; 435 };
397 436
398 applicable_traits 437 located_imports
399} 438}
400 439
401fn get_mod_path( 440fn get_mod_path(
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index 480cbf1ea..fd700e04f 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -17,8 +17,8 @@ use rustc_hash::FxHashSet;
17 17
18pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; 18pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40;
19 19
20pub fn find_exact_imports<'a>( 20pub fn find_exact_imports(
21 sema: &Semantics<'a, RootDatabase>, 21 sema: &Semantics<'_, RootDatabase>,
22 krate: Crate, 22 krate: Crate,
23 name_to_import: String, 23 name_to_import: String,
24) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> { 24) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> {
@@ -48,7 +48,7 @@ pub enum AssocItemSearch {
48} 48}
49 49
50pub fn find_similar_imports<'a>( 50pub fn find_similar_imports<'a>(
51 sema: &Semantics<'a, RootDatabase>, 51 sema: &'a Semantics<'a, RootDatabase>,
52 krate: Crate, 52 krate: Crate,
53 fuzzy_search_string: String, 53 fuzzy_search_string: String,
54 assoc_item_search: AssocItemSearch, 54 assoc_item_search: AssocItemSearch,
@@ -77,12 +77,11 @@ pub fn find_similar_imports<'a>(
77 local_query.limit(limit); 77 local_query.limit(limit);
78 } 78 }
79 79
80 let db = sema.db;
81 Box::new(find_imports(sema, krate, local_query, external_query).filter( 80 Box::new(find_imports(sema, krate, local_query, external_query).filter(
82 move |import_candidate| match assoc_item_search { 81 move |import_candidate| match assoc_item_search {
83 AssocItemSearch::Include => true, 82 AssocItemSearch::Include => true,
84 AssocItemSearch::Exclude => !is_assoc_item(import_candidate, db), 83 AssocItemSearch::Exclude => !is_assoc_item(import_candidate, sema.db),
85 AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, db), 84 AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, sema.db),
86 }, 85 },
87 )) 86 ))
88} 87}