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.rs116
1 files changed, 78 insertions, 38 deletions
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 77fc59b4ec..ac592dfe93 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -3,20 +3,20 @@
use std::ops::ControlFlow;
use hir::{
- db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig,
+ AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, HasCrate, ImportPathConfig,
ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
- SemanticsScope, Trait, TyFingerprint, Type,
+ SemanticsScope, Trait, TyFingerprint, Type, db::HirDatabase,
};
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
- ast::{self, make, HasName},
AstNode, SyntaxNode,
+ ast::{self, HasName, make},
};
use crate::{
- items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
FxIndexSet, RootDatabase,
+ items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
};
/// A candidate for import, derived during various IDE activities:
@@ -183,6 +183,9 @@ impl ImportAssets {
}
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CompleteInFlyimport(pub bool);
+
/// An import (not necessary the only one) that corresponds a certain given [`PathImportCandidate`].
/// (the structure is not entirely correct, since there can be situations requiring two imports, see FIXME below for the details)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -198,11 +201,31 @@ pub struct LocatedImport {
/// the original item is the associated constant, but the import has to be a trait that
/// defines this constant.
pub original_item: ItemInNs,
+ /// The value of `#[rust_analyzer::completions(...)]`, if existing.
+ pub complete_in_flyimport: CompleteInFlyimport,
}
impl LocatedImport {
- pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self {
- Self { import_path, item_to_import, original_item }
+ pub fn new(
+ import_path: ModPath,
+ item_to_import: ItemInNs,
+ original_item: ItemInNs,
+ complete_in_flyimport: CompleteInFlyimport,
+ ) -> Self {
+ Self { import_path, item_to_import, original_item, complete_in_flyimport }
+ }
+
+ pub fn new_no_completion(
+ import_path: ModPath,
+ item_to_import: ItemInNs,
+ original_item: ItemInNs,
+ ) -> Self {
+ Self {
+ import_path,
+ item_to_import,
+ original_item,
+ complete_in_flyimport: CompleteInFlyimport(true),
+ }
}
}
@@ -273,12 +296,13 @@ impl ImportAssets {
Some(it) => it,
None => return <FxIndexSet<_>>::default().into_iter(),
};
+ let db = sema.db;
let krate = self.module_with_candidate.krate();
let scope_definitions = self.scope_definitions(sema);
let mod_path = |item| {
get_mod_path(
- sema.db,
- item_for_path_search(sema.db, item)?,
+ db,
+ item_for_path_search(db, item)?,
&self.module_with_candidate,
prefixed,
cfg,
@@ -288,7 +312,7 @@ impl ImportAssets {
match &self.import_candidate {
ImportCandidate::Path(path_candidate) => path_applicable_imports(
- sema,
+ db,
&scope,
krate,
path_candidate,
@@ -297,7 +321,7 @@ impl ImportAssets {
),
ImportCandidate::TraitAssocItem(trait_candidate)
| ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
- sema,
+ db,
krate,
&scope,
trait_candidate,
@@ -325,7 +349,7 @@ impl ImportAssets {
}
fn path_applicable_imports(
- sema: &Semantics<'_, RootDatabase>,
+ db: &RootDatabase,
scope: &SemanticsScope<'_>,
current_crate: Crate,
path_candidate: &PathImportCandidate,
@@ -337,7 +361,7 @@ fn path_applicable_imports(
match &*path_candidate.qualifier {
[] => {
items_locator::items_with_name(
- sema,
+ db,
current_crate,
path_candidate.name.clone(),
// FIXME: we could look up assoc items by the input and propose those in completion,
@@ -350,12 +374,17 @@ fn path_applicable_imports(
// see also an ignored test under FIXME comment in the qualify_path.rs module
AssocSearchMode::Exclude,
)
- .filter_map(|item| {
+ .filter_map(|(item, do_not_complete)| {
if !scope_filter(item) {
return None;
}
let mod_path = mod_path(item)?;
- Some(LocatedImport::new(mod_path, item, item))
+ Some(LocatedImport::new(
+ mod_path,
+ item,
+ item,
+ CompleteInFlyimport(do_not_complete != Complete::IgnoreFlyimport),
+ ))
})
.take(DEFAULT_QUERY_SEARCH_LIMIT)
.collect()
@@ -365,22 +394,23 @@ fn path_applicable_imports(
// what follows
// FIXME: This doesn't handle visibility
[first_qsegment, qualifier_rest @ ..] => items_locator::items_with_name(
- sema,
+ db,
current_crate,
NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
AssocSearchMode::Exclude,
)
- .filter_map(|item| {
+ .filter_map(|(item, do_not_complete)| {
// 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,
+ db,
scope,
mod_path,
scope_filter,
&path_candidate.name,
item,
qualifier_rest,
+ CompleteInFlyimport(do_not_complete != Complete::IgnoreFlyimport),
)
})
.take(DEFAULT_QUERY_SEARCH_LIMIT)
@@ -391,13 +421,14 @@ fn path_applicable_imports(
/// 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>,
+ db: &RootDatabase,
scope: &SemanticsScope<'_>,
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
scope_filter: impl Fn(ItemInNs) -> bool,
candidate: &NameToImport,
resolved_qualifier: ItemInNs,
unresolved_qualifier: &[Name],
+ complete_in_flyimport: CompleteInFlyimport,
) -> Option<LocatedImport> {
let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
@@ -406,8 +437,8 @@ fn validate_resolvable(
if !unresolved_qualifier.is_empty() {
match resolved_qualifier {
ItemInNs::Types(ModuleDef::Module(module)) => {
- adjusted_resolved_qualifier = sema
- .resolve_mod_path_relative(module, unresolved_qualifier.iter().cloned())?
+ adjusted_resolved_qualifier = module
+ .resolve_mod_path(db, unresolved_qualifier.iter().cloned())?
.next()?;
}
// can't resolve multiple segments for non-module item path bases
@@ -424,7 +455,7 @@ fn validate_resolvable(
let ty = match qualifier {
ModuleDef::Module(module) => {
return items_locator::items_with_name_in_module(
- sema,
+ db,
module,
candidate.clone(),
AssocSearchMode::Exclude,
@@ -433,23 +464,30 @@ fn validate_resolvable(
false => ControlFlow::Continue(()),
},
)
- .map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item))
+ .map(|item| {
+ LocatedImport::new(
+ import_path_candidate,
+ resolved_qualifier,
+ item,
+ complete_in_flyimport,
+ )
+ });
}
// FIXME
ModuleDef::Trait(_) => return None,
// FIXME
ModuleDef::TraitAlias(_) => return None,
- ModuleDef::TypeAlias(alias) => alias.ty(sema.db),
- ModuleDef::BuiltinType(builtin) => builtin.ty(sema.db),
- ModuleDef::Adt(adt) => adt.ty(sema.db),
+ ModuleDef::TypeAlias(alias) => alias.ty(db),
+ ModuleDef::BuiltinType(builtin) => builtin.ty(db),
+ ModuleDef::Adt(adt) => adt.ty(db),
_ => return None,
};
- ty.iterate_path_candidates(sema.db, scope, &FxHashSet::default(), None, None, |assoc| {
+ ty.iterate_path_candidates(db, scope, &FxHashSet::default(), None, None, |assoc| {
// FIXME: Support extra trait imports
- if assoc.container_or_implemented_trait(sema.db).is_some() {
+ if assoc.container_or_implemented_trait(db).is_some() {
return None;
}
- let name = assoc.name(sema.db)?;
+ let name = assoc.name(db)?;
let is_match = match candidate {
NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
NameToImport::Prefix(text, false) => {
@@ -471,6 +509,7 @@ fn validate_resolvable(
import_path_candidate.clone(),
resolved_qualifier,
assoc_to_item(assoc),
+ complete_in_flyimport,
))
})
}
@@ -495,7 +534,7 @@ fn item_for_path_search_assoc(db: &RootDatabase, assoc_item: AssocItem) -> Optio
}
fn trait_applicable_items(
- sema: &Semantics<'_, RootDatabase>,
+ db: &RootDatabase,
current_crate: Crate,
scope: &SemanticsScope<'_>,
trait_candidate: &TraitImportCandidate,
@@ -505,21 +544,19 @@ fn trait_applicable_items(
) -> FxIndexSet<LocatedImport> {
let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered();
- let db = sema.db;
-
let inherent_traits = trait_candidate.receiver_ty.applicable_inherent_traits(db);
let env_traits = trait_candidate.receiver_ty.env_traits(db);
let related_traits = inherent_traits.chain(env_traits).collect::<FxHashSet<_>>();
- let mut required_assoc_items = FxHashSet::default();
+ let mut required_assoc_items = FxHashMap::default();
let mut trait_candidates: FxHashSet<_> = items_locator::items_with_name(
- sema,
+ db,
current_crate,
trait_candidate.assoc_item_name.clone(),
AssocSearchMode::AssocItemsOnly,
)
- .filter_map(|input| item_as_assoc(db, input))
- .filter_map(|assoc| {
+ .filter_map(|(input, do_not_complete)| Some((item_as_assoc(db, input)?, do_not_complete)))
+ .filter_map(|(assoc, do_not_complete)| {
if !trait_assoc_item && matches!(assoc, AssocItem::Const(_) | AssocItem::TypeAlias(_)) {
return None;
}
@@ -528,7 +565,8 @@ fn trait_applicable_items(
if related_traits.contains(&assoc_item_trait) {
return None;
}
- required_assoc_items.insert(assoc);
+ required_assoc_items
+ .insert(assoc, CompleteInFlyimport(do_not_complete != Complete::IgnoreFlyimport));
Some(assoc_item_trait.into())
})
.collect();
@@ -600,7 +638,7 @@ fn trait_applicable_items(
None,
None,
|assoc| {
- if required_assoc_items.contains(&assoc) {
+ if let Some(&complete_in_flyimport) = required_assoc_items.get(&assoc) {
let located_trait = assoc.container_trait(db).filter(|&it| scope_filter(it))?;
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
let import_path = trait_import_paths
@@ -611,6 +649,7 @@ fn trait_applicable_items(
import_path,
trait_item,
assoc_to_item(assoc),
+ complete_in_flyimport,
));
}
None::<()>
@@ -625,7 +664,7 @@ fn trait_applicable_items(
None,
|function| {
let assoc = function.as_assoc_item(db)?;
- if required_assoc_items.contains(&assoc) {
+ if let Some(&complete_in_flyimport) = required_assoc_items.get(&assoc) {
let located_trait = assoc.container_trait(db).filter(|&it| scope_filter(it))?;
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
let import_path = trait_import_paths
@@ -636,6 +675,7 @@ fn trait_applicable_items(
import_path,
trait_item,
assoc_to_item(assoc),
+ complete_in_flyimport,
));
}
None::<()>