Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/imports/import_assets.rs')
-rw-r--r--crates/ide-db/src/imports/import_assets.rs43
1 files changed, 32 insertions, 11 deletions
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 8f0be1d903..ad86d855b5 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -1,15 +1,17 @@
//! Look up accessible paths for items.
+use std::ops::ControlFlow;
+
use hir::{
db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig,
- ItemInNs, ModPath, Module, ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics,
+ ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
SemanticsScope, Trait, TyFingerprint, Type,
};
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
ast::{self, make, HasName},
- AstNode, SmolStr, SyntaxNode,
+ AstNode, SyntaxNode,
};
use crate::{
@@ -51,7 +53,7 @@ pub struct TraitImportCandidate {
#[derive(Debug)]
pub struct PathImportCandidate {
/// Optional qualifier before name.
- pub qualifier: Vec<SmolStr>,
+ pub qualifier: Vec<Name>,
/// The name the item (struct, trait, enum, etc.) should have.
pub name: NameToImport,
}
@@ -70,10 +72,18 @@ pub enum NameToImport {
impl NameToImport {
pub fn exact_case_sensitive(s: String) -> NameToImport {
+ let s = match s.strip_prefix("r#") {
+ Some(s) => s.to_owned(),
+ None => s,
+ };
NameToImport::Exact(s, true)
}
pub fn fuzzy(s: String) -> NameToImport {
+ let s = match s.strip_prefix("r#") {
+ Some(s) => s.to_owned(),
+ None => s,
+ };
// unless all chars are lowercase, we do a case sensitive search
let case_sensitive = s.chars().any(|c| c.is_uppercase());
NameToImport::Fuzzy(s, case_sensitive)
@@ -350,21 +360,27 @@ fn path_applicable_imports(
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
.collect()
}
+ // we have some unresolved qualifier that we search an import for
+ // The key here is that whatever we import must form a resolved path for the remainder of
+ // what follows
+ // FIXME: This doesn't handle visibility
[first_qsegment, qualifier_rest @ ..] => items_locator::items_with_name(
sema,
current_crate,
- NameToImport::Exact(first_qsegment.to_string(), true),
+ NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
AssocSearchMode::Exclude,
)
.filter_map(|item| {
- import_for_item(
+ // we found imports for `first_qsegment`, now we need to filter these imports by whether
+ // they result in resolving the rest of the path successfully
+ validate_resolvable(
sema,
scope,
mod_path,
+ scope_filter,
&path_candidate.name,
item,
qualifier_rest,
- scope_filter,
)
})
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
@@ -372,14 +388,16 @@ fn path_applicable_imports(
}
}
-fn import_for_item(
+/// Validates and builds an import for `resolved_qualifier` if the `unresolved_qualifier` appended
+/// to it resolves and there is a validate `candidate` after that.
+fn validate_resolvable(
sema: &Semantics<'_, RootDatabase>,
scope: &SemanticsScope<'_>,
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
+ scope_filter: impl Fn(ItemInNs) -> bool,
candidate: &NameToImport,
resolved_qualifier: ItemInNs,
- unresolved_qualifier: &[SmolStr],
- scope_filter: impl Fn(ItemInNs) -> bool,
+ unresolved_qualifier: &[Name],
) -> Option<LocatedImport> {
let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
@@ -410,8 +428,11 @@ fn import_for_item(
module,
candidate.clone(),
AssocSearchMode::Exclude,
+ |it| match scope_filter(it) {
+ true => ControlFlow::Break(it),
+ false => ControlFlow::Continue(()),
+ },
)
- .find(|&it| scope_filter(it))
.map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item))
}
// FIXME
@@ -709,7 +730,7 @@ fn path_import_candidate(
if qualifier.first_qualifier().is_none_or(|it| sema.resolve_path(&it).is_none()) {
let qualifier = qualifier
.segments()
- .map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text())))
+ .map(|seg| seg.name_ref().map(|name| Name::new_root(&name.text())))
.collect::<Option<Vec<_>>>()?;
ImportCandidate::Path(PathImportCandidate { qualifier, name })
} else {