diff options
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 192 |
1 files changed, 97 insertions, 95 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index a080b6ca7..517abbb4b 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{AsAssocItem, AssocItem, Module, ModuleDef, PrefixKind, Semantics}; | 3 | use hir::{AsAssocItem, AssocItem, Crate, MacroDef, Module, ModuleDef, PrefixKind, Semantics}; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use syntax::{ast, AstNode}; | 5 | use syntax::{ast, AstNode}; |
6 | 6 | ||
@@ -168,73 +168,8 @@ impl ImportAssets { | |||
168 | sema: &Semantics<RootDatabase>, | 168 | sema: &Semantics<RootDatabase>, |
169 | prefixed: Option<hir::PrefixKind>, | 169 | prefixed: Option<hir::PrefixKind>, |
170 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { | 170 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { |
171 | let db = sema.db; | ||
172 | let mut trait_candidates = FxHashSet::default(); | ||
173 | let current_crate = self.module_with_candidate.krate(); | 171 | let current_crate = self.module_with_candidate.krate(); |
174 | 172 | ||
175 | let filter = |candidate: Either<hir::ModuleDef, hir::MacroDef>| { | ||
176 | // TODO kb process all traits at once instead? | ||
177 | trait_candidates.clear(); | ||
178 | match &self.import_candidate { | ||
179 | ImportCandidate::TraitAssocItem(trait_candidate) => { | ||
180 | let canidate_assoc_item = match candidate { | ||
181 | Either::Left(module_def) => module_def.as_assoc_item(db), | ||
182 | _ => None, | ||
183 | }?; | ||
184 | trait_candidates.insert(canidate_assoc_item.containing_trait(db)?.into()); | ||
185 | |||
186 | trait_candidate | ||
187 | .receiver_ty | ||
188 | .iterate_path_candidates( | ||
189 | db, | ||
190 | current_crate, | ||
191 | &trait_candidates, | ||
192 | None, | ||
193 | |_, assoc| { | ||
194 | if canidate_assoc_item == assoc { | ||
195 | if let AssocItem::Function(f) = assoc { | ||
196 | if f.self_param(db).is_some() { | ||
197 | return None; | ||
198 | } | ||
199 | } | ||
200 | Some(assoc_to_module_def(assoc)) | ||
201 | } else { | ||
202 | None | ||
203 | } | ||
204 | }, | ||
205 | ) | ||
206 | .map(Either::Left) | ||
207 | } | ||
208 | ImportCandidate::TraitMethod(trait_candidate) => { | ||
209 | let canidate_assoc_item = match candidate { | ||
210 | Either::Left(module_def) => module_def.as_assoc_item(db), | ||
211 | _ => None, | ||
212 | }?; | ||
213 | trait_candidates.insert(canidate_assoc_item.containing_trait(db)?.into()); | ||
214 | |||
215 | trait_candidate | ||
216 | .receiver_ty | ||
217 | .iterate_method_candidates( | ||
218 | db, | ||
219 | current_crate, | ||
220 | &trait_candidates, | ||
221 | None, | ||
222 | |_, function| { | ||
223 | let assoc = function.as_assoc_item(db)?; | ||
224 | if canidate_assoc_item == assoc { | ||
225 | Some(assoc_to_module_def(assoc)) | ||
226 | } else { | ||
227 | None | ||
228 | } | ||
229 | }, | ||
230 | ) | ||
231 | .map(ModuleDef::from) | ||
232 | .map(Either::Left) | ||
233 | } | ||
234 | _ => Some(candidate), | ||
235 | } | ||
236 | }; | ||
237 | |||
238 | let unfiltered_imports = match self.name_to_import() { | 173 | let unfiltered_imports = match self.name_to_import() { |
239 | NameToImport::Exact(exact_name) => { | 174 | NameToImport::Exact(exact_name) => { |
240 | imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) | 175 | imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) |
@@ -261,42 +196,109 @@ impl ImportAssets { | |||
261 | } | 196 | } |
262 | }; | 197 | }; |
263 | 198 | ||
264 | let mut res = unfiltered_imports | 199 | let db = sema.db; |
265 | .filter_map(filter) | 200 | let mut res = |
266 | .filter_map(|candidate| { | 201 | applicable_defs(self.import_candidate(), current_crate, db, unfiltered_imports) |
267 | let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into); | 202 | .filter_map(|candidate| { |
203 | let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into); | ||
268 | 204 | ||
269 | let item_to_search = match self.import_candidate { | 205 | let item_to_search = match self.import_candidate { |
270 | ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => { | 206 | ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => { |
271 | let canidate_trait = match candidate { | 207 | let canidate_trait = match candidate { |
272 | Either::Left(module_def) => { | 208 | Either::Left(module_def) => { |
273 | module_def.as_assoc_item(db)?.containing_trait(db) | 209 | module_def.as_assoc_item(db)?.containing_trait(db) |
274 | } | 210 | } |
275 | _ => None, | 211 | _ => None, |
276 | }?; | 212 | }?; |
277 | ModuleDef::from(canidate_trait).into() | 213 | ModuleDef::from(canidate_trait).into() |
278 | } | 214 | } |
279 | _ => item, | 215 | _ => item, |
280 | }; | 216 | }; |
281 | 217 | ||
282 | if let Some(prefix_kind) = prefixed { | 218 | if let Some(prefix_kind) = prefixed { |
283 | self.module_with_candidate.find_use_path_prefixed( | 219 | self.module_with_candidate.find_use_path_prefixed( |
284 | db, | 220 | db, |
285 | item_to_search, | 221 | item_to_search, |
286 | prefix_kind, | 222 | prefix_kind, |
287 | ) | 223 | ) |
288 | } else { | 224 | } else { |
289 | self.module_with_candidate.find_use_path(db, item_to_search) | 225 | self.module_with_candidate.find_use_path(db, item_to_search) |
290 | } | 226 | } |
291 | .map(|path| (path, item)) | 227 | .map(|path| (path, item)) |
292 | }) | 228 | }) |
293 | .filter(|(use_path, _)| use_path.len() > 1) | 229 | .filter(|(use_path, _)| use_path.len() > 1) |
294 | .collect::<Vec<_>>(); | 230 | .collect::<Vec<_>>(); |
295 | res.sort_by_cached_key(|(path, _)| path.clone()); | 231 | res.sort_by_cached_key(|(path, _)| path.clone()); |
296 | res | 232 | res |
297 | } | 233 | } |
298 | } | 234 | } |
299 | 235 | ||
236 | fn applicable_defs<'a>( | ||
237 | import_candidate: &ImportCandidate, | ||
238 | current_crate: Crate, | ||
239 | db: &RootDatabase, | ||
240 | unfiltered_imports: Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a>, | ||
241 | ) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a> { | ||
242 | let receiver_ty = match import_candidate { | ||
243 | ImportCandidate::Path(_) => return unfiltered_imports, | ||
244 | ImportCandidate::TraitAssocItem(candidate) | ImportCandidate::TraitMethod(candidate) => { | ||
245 | &candidate.receiver_ty | ||
246 | } | ||
247 | }; | ||
248 | |||
249 | let mut required_assoc_items = FxHashSet::default(); | ||
250 | |||
251 | let trait_candidates = unfiltered_imports | ||
252 | .filter_map(|input| match input { | ||
253 | Either::Left(module_def) => module_def.as_assoc_item(db), | ||
254 | _ => None, | ||
255 | }) | ||
256 | .filter_map(|assoc| { | ||
257 | let assoc_item_trait = assoc.containing_trait(db)?; | ||
258 | required_assoc_items.insert(assoc); | ||
259 | Some(assoc_item_trait.into()) | ||
260 | }) | ||
261 | .collect(); | ||
262 | |||
263 | let mut applicable_defs = FxHashSet::default(); | ||
264 | |||
265 | match import_candidate { | ||
266 | ImportCandidate::Path(_) => unreachable!(), | ||
267 | ImportCandidate::TraitAssocItem(_) => receiver_ty.iterate_path_candidates( | ||
268 | db, | ||
269 | current_crate, | ||
270 | &trait_candidates, | ||
271 | None, | ||
272 | |_, assoc| { | ||
273 | if required_assoc_items.contains(&assoc) { | ||
274 | if let AssocItem::Function(f) = assoc { | ||
275 | if f.self_param(db).is_some() { | ||
276 | return None; | ||
277 | } | ||
278 | } | ||
279 | applicable_defs.insert(Either::Left(assoc_to_module_def(assoc))); | ||
280 | } | ||
281 | None::<()> | ||
282 | }, | ||
283 | ), | ||
284 | ImportCandidate::TraitMethod(_) => receiver_ty.iterate_method_candidates( | ||
285 | db, | ||
286 | current_crate, | ||
287 | &trait_candidates, | ||
288 | None, | ||
289 | |_, function| { | ||
290 | let assoc = function.as_assoc_item(db)?; | ||
291 | if required_assoc_items.contains(&assoc) { | ||
292 | applicable_defs.insert(Either::Left(assoc_to_module_def(assoc))); | ||
293 | } | ||
294 | None::<()> | ||
295 | }, | ||
296 | ), | ||
297 | }; | ||
298 | |||
299 | Box::new(applicable_defs.into_iter()) | ||
300 | } | ||
301 | |||
300 | fn assoc_to_module_def(assoc: AssocItem) -> ModuleDef { | 302 | fn assoc_to_module_def(assoc: AssocItem) -> ModuleDef { |
301 | match assoc { | 303 | match assoc { |
302 | AssocItem::Function(f) => f.into(), | 304 | AssocItem::Function(f) => f.into(), |