diff options
Diffstat (limited to 'crates/ide_db/src')
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 150 |
1 files changed, 65 insertions, 85 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 517abbb4b..513128eae 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -31,7 +31,7 @@ pub struct TraitImportCandidate { | |||
31 | 31 | ||
32 | #[derive(Debug)] | 32 | #[derive(Debug)] |
33 | pub struct PathImportCandidate { | 33 | pub struct PathImportCandidate { |
34 | pub qualifier: Option<ast::Path>, | 34 | pub unresolved_qualifier: Option<ast::Path>, |
35 | pub name: NameToImport, | 35 | pub name: NameToImport, |
36 | } | 36 | } |
37 | 37 | ||
@@ -82,38 +82,14 @@ impl ImportAssets { | |||
82 | } | 82 | } |
83 | 83 | ||
84 | pub fn for_fuzzy_path( | 84 | pub fn for_fuzzy_path( |
85 | module_with_path: Module, | 85 | module_with_candidate: Module, |
86 | qualifier: Option<ast::Path>, | 86 | qualifier: Option<ast::Path>, |
87 | fuzzy_name: String, | 87 | fuzzy_name: String, |
88 | sema: &Semantics<RootDatabase>, | 88 | sema: &Semantics<RootDatabase>, |
89 | ) -> Option<Self> { | 89 | ) -> Option<Self> { |
90 | Some(match qualifier { | 90 | Some(Self { |
91 | Some(qualifier) => { | 91 | import_candidate: ImportCandidate::for_fuzzy_path(qualifier, fuzzy_name, sema)?, |
92 | let qualifier_resolution = sema.resolve_path(&qualifier)?; | 92 | module_with_candidate, |
93 | match qualifier_resolution { | ||
94 | hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => Self { | ||
95 | import_candidate: ImportCandidate::TraitAssocItem(TraitImportCandidate { | ||
96 | receiver_ty: assoc_item_path.ty(sema.db), | ||
97 | name: NameToImport::Fuzzy(fuzzy_name), | ||
98 | }), | ||
99 | module_with_candidate: module_with_path, | ||
100 | }, | ||
101 | _ => Self { | ||
102 | import_candidate: ImportCandidate::Path(PathImportCandidate { | ||
103 | qualifier: Some(qualifier), | ||
104 | name: NameToImport::Fuzzy(fuzzy_name), | ||
105 | }), | ||
106 | module_with_candidate: module_with_path, | ||
107 | }, | ||
108 | } | ||
109 | } | ||
110 | None => Self { | ||
111 | import_candidate: ImportCandidate::Path(PathImportCandidate { | ||
112 | qualifier: None, | ||
113 | name: NameToImport::Fuzzy(fuzzy_name), | ||
114 | }), | ||
115 | module_with_candidate: module_with_path, | ||
116 | }, | ||
117 | }) | 93 | }) |
118 | } | 94 | } |
119 | 95 | ||
@@ -169,8 +145,9 @@ impl ImportAssets { | |||
169 | prefixed: Option<hir::PrefixKind>, | 145 | prefixed: Option<hir::PrefixKind>, |
170 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { | 146 | ) -> Vec<(hir::ModPath, hir::ItemInNs)> { |
171 | let current_crate = self.module_with_candidate.krate(); | 147 | let current_crate = self.module_with_candidate.krate(); |
148 | let import_candidate = &self.import_candidate; | ||
172 | 149 | ||
173 | let unfiltered_imports = match self.name_to_import() { | 150 | let imports_for_candidate_name = match self.name_to_import() { |
174 | NameToImport::Exact(exact_name) => { | 151 | NameToImport::Exact(exact_name) => { |
175 | imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) | 152 | imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) |
176 | } | 153 | } |
@@ -180,11 +157,10 @@ impl ImportAssets { | |||
180 | // and https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Blanket.20trait.20impls.20lookup | 157 | // and https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Blanket.20trait.20impls.20lookup |
181 | // for the details | 158 | // for the details |
182 | NameToImport::Fuzzy(fuzzy_name) => { | 159 | NameToImport::Fuzzy(fuzzy_name) => { |
183 | let (assoc_item_search, limit) = match self.import_candidate { | 160 | let (assoc_item_search, limit) = if import_candidate.is_trait_candidate() { |
184 | ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => { | 161 | (AssocItemSearch::AssocItemsOnly, None) |
185 | (AssocItemSearch::AssocItemsOnly, None) | 162 | } else { |
186 | } | 163 | (AssocItemSearch::Exclude, Some(DEFAULT_QUERY_SEARCH_LIMIT)) |
187 | _ => (AssocItemSearch::Exclude, Some(DEFAULT_QUERY_SEARCH_LIMIT)), | ||
188 | }; | 164 | }; |
189 | imports_locator::find_similar_imports( | 165 | imports_locator::find_similar_imports( |
190 | sema, | 166 | sema, |
@@ -198,24 +174,22 @@ impl ImportAssets { | |||
198 | 174 | ||
199 | let db = sema.db; | 175 | let db = sema.db; |
200 | let mut res = | 176 | let mut res = |
201 | applicable_defs(self.import_candidate(), current_crate, db, unfiltered_imports) | 177 | applicable_defs(import_candidate, current_crate, db, imports_for_candidate_name) |
202 | .filter_map(|candidate| { | 178 | .filter_map(|candidate| { |
203 | let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into); | 179 | let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into); |
204 | 180 | ||
205 | let item_to_search = match self.import_candidate { | 181 | let item_to_search = if import_candidate.is_trait_candidate() { |
206 | ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => { | 182 | let canidate_trait = match candidate { |
207 | let canidate_trait = match candidate { | 183 | Either::Left(module_def) => { |
208 | Either::Left(module_def) => { | 184 | module_def.as_assoc_item(db)?.containing_trait(db) |
209 | module_def.as_assoc_item(db)?.containing_trait(db) | 185 | } |
210 | } | 186 | _ => None, |
211 | _ => None, | 187 | }?; |
212 | }?; | 188 | ModuleDef::from(canidate_trait).into() |
213 | ModuleDef::from(canidate_trait).into() | 189 | } else { |
214 | } | 190 | item |
215 | _ => item, | ||
216 | }; | 191 | }; |
217 | 192 | let mod_path = if let Some(prefix_kind) = prefixed { | |
218 | if let Some(prefix_kind) = prefixed { | ||
219 | self.module_with_candidate.find_use_path_prefixed( | 193 | self.module_with_candidate.find_use_path_prefixed( |
220 | db, | 194 | db, |
221 | item_to_search, | 195 | item_to_search, |
@@ -223,8 +197,9 @@ impl ImportAssets { | |||
223 | ) | 197 | ) |
224 | } else { | 198 | } else { |
225 | self.module_with_candidate.find_use_path(db, item_to_search) | 199 | self.module_with_candidate.find_use_path(db, item_to_search) |
226 | } | 200 | }; |
227 | .map(|path| (path, item)) | 201 | |
202 | mod_path.zip(Some(item)) | ||
228 | }) | 203 | }) |
229 | .filter(|(use_path, _)| use_path.len() > 1) | 204 | .filter(|(use_path, _)| use_path.len() > 1) |
230 | .collect::<Vec<_>>(); | 205 | .collect::<Vec<_>>(); |
@@ -239,6 +214,7 @@ fn applicable_defs<'a>( | |||
239 | db: &RootDatabase, | 214 | db: &RootDatabase, |
240 | unfiltered_imports: Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a>, | 215 | unfiltered_imports: Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a>, |
241 | ) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a> { | 216 | ) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a> { |
217 | // TODO kb this needs to consider various path prefixes, etc. | ||
242 | let receiver_ty = match import_candidate { | 218 | let receiver_ty = match import_candidate { |
243 | ImportCandidate::Path(_) => return unfiltered_imports, | 219 | ImportCandidate::Path(_) => return unfiltered_imports, |
244 | ImportCandidate::TraitAssocItem(candidate) | ImportCandidate::TraitMethod(candidate) => { | 220 | ImportCandidate::TraitAssocItem(candidate) | ImportCandidate::TraitMethod(candidate) => { |
@@ -325,41 +301,45 @@ impl ImportCandidate { | |||
325 | if sema.resolve_path(path).is_some() { | 301 | if sema.resolve_path(path).is_some() { |
326 | return None; | 302 | return None; |
327 | } | 303 | } |
304 | path_import_candidate( | ||
305 | sema, | ||
306 | path.qualifier(), | ||
307 | NameToImport::Exact(path.segment()?.name_ref()?.to_string()), | ||
308 | ) | ||
309 | } | ||
328 | 310 | ||
329 | let segment = path.segment()?; | 311 | fn for_fuzzy_path( |
330 | let candidate = if let Some(qualifier) = path.qualifier() { | 312 | qualifier: Option<ast::Path>, |
331 | let qualifier_start = qualifier.syntax().descendants().find_map(ast::NameRef::cast)?; | 313 | fuzzy_name: String, |
332 | let qualifier_start_path = | 314 | sema: &Semantics<RootDatabase>, |
333 | qualifier_start.syntax().ancestors().find_map(ast::Path::cast)?; | 315 | ) -> Option<Self> { |
334 | if let Some(qualifier_start_resolution) = sema.resolve_path(&qualifier_start_path) { | 316 | path_import_candidate(sema, qualifier, NameToImport::Fuzzy(fuzzy_name)) |
335 | let qualifier_resolution = if qualifier_start_path == qualifier { | 317 | } |
336 | qualifier_start_resolution | 318 | |
337 | } else { | 319 | fn is_trait_candidate(&self) -> bool { |
338 | sema.resolve_path(&qualifier)? | 320 | matches!(self, ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_)) |
339 | }; | 321 | } |
340 | match qualifier_resolution { | 322 | } |
341 | hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => { | 323 | |
342 | ImportCandidate::TraitAssocItem(TraitImportCandidate { | 324 | fn path_import_candidate( |
343 | receiver_ty: assoc_item_path.ty(sema.db), | 325 | sema: &Semantics<RootDatabase>, |
344 | name: NameToImport::Exact(segment.name_ref()?.to_string()), | 326 | qualifier: Option<ast::Path>, |
345 | }) | 327 | name: NameToImport, |
346 | } | 328 | ) -> Option<ImportCandidate> { |
347 | _ => return None, | 329 | Some(match qualifier { |
348 | } | 330 | Some(qualifier) => match sema.resolve_path(&qualifier) { |
349 | } else { | 331 | None => ImportCandidate::Path(PathImportCandidate { |
350 | ImportCandidate::Path(PathImportCandidate { | 332 | unresolved_qualifier: Some(qualifier), |
351 | qualifier: Some(qualifier), | 333 | name, |
352 | name: NameToImport::Exact(qualifier_start.to_string()), | 334 | }), |
335 | Some(hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path))) => { | ||
336 | ImportCandidate::TraitAssocItem(TraitImportCandidate { | ||
337 | receiver_ty: assoc_item_path.ty(sema.db), | ||
338 | name, | ||
353 | }) | 339 | }) |
354 | } | 340 | } |
355 | } else { | 341 | Some(_) => return None, |
356 | ImportCandidate::Path(PathImportCandidate { | 342 | }, |
357 | qualifier: None, | 343 | None => ImportCandidate::Path(PathImportCandidate { unresolved_qualifier: None, name }), |
358 | name: NameToImport::Exact( | 344 | }) |
359 | segment.syntax().descendants().find_map(ast::NameRef::cast)?.to_string(), | ||
360 | ), | ||
361 | }) | ||
362 | }; | ||
363 | Some(candidate) | ||
364 | } | ||
365 | } | 345 | } |