Skip to content

Commit 311d22c

Browse files
authored
Merge pull request rust-lang#20919 from ChayimFriedman2/qualifier-many-flyimport
fix: Consider all matches for flyimport even when searched with a qualifier
2 parents f7a13f0 + 4c709ba commit 311d22c

File tree

2 files changed

+86
-52
lines changed

2 files changed

+86
-52
lines changed

crates/ide-completion/src/tests/flyimport.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,3 +1953,25 @@ fn foo() {
19531953
expect![""],
19541954
);
19551955
}
1956+
1957+
#[test]
1958+
fn multiple_matches_with_qualifier() {
1959+
check(
1960+
r#"
1961+
//- /foo.rs crate:foo
1962+
pub mod env {
1963+
pub fn var() {}
1964+
pub fn _var() {}
1965+
}
1966+
1967+
//- /bar.rs crate:bar deps:foo
1968+
fn main() {
1969+
env::var$0
1970+
}
1971+
"#,
1972+
expect![[r#"
1973+
fn _var() (use foo::env) fn()
1974+
fn var() (use foo::env) fn()
1975+
"#]],
1976+
);
1977+
}

crates/ide-db/src/imports/import_assets.rs

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Look up accessible paths for items.
22
3-
use std::ops::ControlFlow;
3+
use std::{convert::Infallible, ops::ControlFlow};
44

55
use hir::{
66
AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, FindPathConfig, HasCrate,
@@ -9,6 +9,7 @@ use hir::{
99
};
1010
use itertools::Itertools;
1111
use rustc_hash::{FxHashMap, FxHashSet};
12+
use smallvec::SmallVec;
1213
use syntax::{
1314
AstNode, SyntaxNode,
1415
ast::{self, HasName, make},
@@ -416,7 +417,7 @@ fn path_applicable_imports(
416417
NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
417418
AssocSearchMode::Exclude,
418419
)
419-
.filter_map(|(item, do_not_complete)| {
420+
.flat_map(|(item, do_not_complete)| {
420421
// we found imports for `first_qsegment`, now we need to filter these imports by whether
421422
// they result in resolving the rest of the path successfully
422423
validate_resolvable(
@@ -446,10 +447,10 @@ fn validate_resolvable(
446447
resolved_qualifier: ItemInNs,
447448
unresolved_qualifier: &[Name],
448449
complete_in_flyimport: CompleteInFlyimport,
449-
) -> Option<LocatedImport> {
450+
) -> SmallVec<[LocatedImport; 1]> {
450451
let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
451452

452-
let qualifier = {
453+
let qualifier = (|| {
453454
let mut adjusted_resolved_qualifier = resolved_qualifier;
454455
if !unresolved_qualifier.is_empty() {
455456
match resolved_qualifier {
@@ -464,69 +465,80 @@ fn validate_resolvable(
464465
}
465466

466467
match adjusted_resolved_qualifier {
467-
ItemInNs::Types(def) => def,
468-
_ => return None,
468+
ItemInNs::Types(def) => Some(def),
469+
_ => None,
469470
}
470-
};
471-
let import_path_candidate = mod_path(resolved_qualifier)?;
471+
})();
472+
let Some(qualifier) = qualifier else { return SmallVec::new() };
473+
let Some(import_path_candidate) = mod_path(resolved_qualifier) else { return SmallVec::new() };
474+
let mut result = SmallVec::new();
472475
let ty = match qualifier {
473476
ModuleDef::Module(module) => {
474-
return items_locator::items_with_name_in_module(
477+
items_locator::items_with_name_in_module::<Infallible>(
475478
db,
476479
module,
477480
candidate.clone(),
478481
AssocSearchMode::Exclude,
479-
|it| match scope_filter(it) {
480-
true => ControlFlow::Break(it),
481-
false => ControlFlow::Continue(()),
482+
|item| {
483+
if scope_filter(item) {
484+
result.push(LocatedImport::new(
485+
import_path_candidate.clone(),
486+
resolved_qualifier,
487+
item,
488+
complete_in_flyimport,
489+
));
490+
}
491+
ControlFlow::Continue(())
482492
},
483-
)
484-
.map(|item| {
485-
LocatedImport::new(
486-
import_path_candidate,
487-
resolved_qualifier,
488-
item,
489-
complete_in_flyimport,
490-
)
491-
});
493+
);
494+
return result;
492495
}
493496
// FIXME
494-
ModuleDef::Trait(_) => return None,
497+
ModuleDef::Trait(_) => return SmallVec::new(),
495498
ModuleDef::TypeAlias(alias) => alias.ty(db),
496499
ModuleDef::BuiltinType(builtin) => builtin.ty(db),
497500
ModuleDef::Adt(adt) => adt.ty(db),
498-
_ => return None,
501+
_ => return SmallVec::new(),
499502
};
500-
ty.iterate_path_candidates(db, scope, &FxHashSet::default(), None, None, |assoc| {
501-
// FIXME: Support extra trait imports
502-
if assoc.container_or_implemented_trait(db).is_some() {
503-
return None;
504-
}
505-
let name = assoc.name(db)?;
506-
let is_match = match candidate {
507-
NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
508-
NameToImport::Prefix(text, false) => {
509-
name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
510-
name_char.eq_ignore_ascii_case(&candidate_char)
511-
})
503+
ty.iterate_path_candidates::<Infallible>(
504+
db,
505+
scope,
506+
&FxHashSet::default(),
507+
None,
508+
None,
509+
|assoc| {
510+
// FIXME: Support extra trait imports
511+
if assoc.container_or_implemented_trait(db).is_some() {
512+
return None;
512513
}
513-
NameToImport::Exact(text, true) => name.as_str() == text,
514-
NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
515-
NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
516-
NameToImport::Fuzzy(text, false) => text
517-
.chars()
518-
.all(|c| name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))),
519-
};
520-
if !is_match {
521-
return None;
522-
}
523-
Some(LocatedImport::new(
524-
import_path_candidate.clone(),
525-
resolved_qualifier,
526-
assoc_to_item(assoc),
527-
complete_in_flyimport,
528-
))
529-
})
514+
let name = assoc.name(db)?;
515+
let is_match = match candidate {
516+
NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
517+
NameToImport::Prefix(text, false) => {
518+
name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
519+
name_char.eq_ignore_ascii_case(&candidate_char)
520+
})
521+
}
522+
NameToImport::Exact(text, true) => name.as_str() == text,
523+
NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
524+
NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
525+
NameToImport::Fuzzy(text, false) => text.chars().all(|c| {
526+
name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))
527+
}),
528+
};
529+
if !is_match {
530+
return None;
531+
}
532+
result.push(LocatedImport::new(
533+
import_path_candidate.clone(),
534+
resolved_qualifier,
535+
assoc_to_item(assoc),
536+
complete_in_flyimport,
537+
));
538+
None
539+
},
540+
);
541+
result
530542
}
531543

532544
pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {

0 commit comments

Comments
 (0)