diff options
author | Kirill Bulatov <[email protected]> | 2021-02-24 23:06:31 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2021-03-08 21:59:18 +0000 |
commit | 582cee2cdf5355b681f14bbb33bd5c431c284d87 (patch) | |
tree | 47d25e9c057759b1aa334abf3f584f1d0317d941 /crates/ide_db/src | |
parent | 309421c117fc20e58b9f30fb28a01a89f50b0086 (diff) |
Return more data about located imports
Diffstat (limited to 'crates/ide_db/src')
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 179 | ||||
-rw-r--r-- | crates/ide_db/src/imports_locator.rs | 11 |
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)] | ||
121 | pub struct LocatedImport { | ||
122 | import_path: ModPath, | ||
123 | item_to_import: ItemInNs, | ||
124 | import_display_override: Option<(ModPath, ItemInNs)>, | ||
125 | } | ||
126 | |||
127 | impl 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 | |||
120 | impl ImportAssets { | 156 | impl 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 | ||
232 | fn path_applicable_items<'a>( | 258 | fn 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 | ||
339 | fn trait_applicable_defs<'a>( | 368 | fn 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 | ||
401 | fn get_mod_path( | 440 | fn 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 | ||
18 | pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; | 18 | pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; |
19 | 19 | ||
20 | pub fn find_exact_imports<'a>( | 20 | pub 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 | ||
50 | pub fn find_similar_imports<'a>( | 50 | pub 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 | } |