aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_db/src/helpers')
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs150
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)]
33pub struct PathImportCandidate { 33pub 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 { 324fn 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}