Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/expr.rs')
-rw-r--r--crates/ide-completion/src/completions/expr.rs145
1 files changed, 136 insertions, 9 deletions
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index f9717f1c2c..fb9955c5e8 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -1,6 +1,7 @@
//! Completion of names from the current scope in expression position.
use hir::ScopeDef;
+use ide_db::FxHashSet;
use crate::{
context::{PathCompletionCtx, PathKind, PathQualifierCtx},
@@ -20,8 +21,129 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
_ => return,
};
+ let scope_def_applicable = |def| {
+ use hir::{GenericParam::*, ModuleDef::*};
+ match def {
+ ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
+ // Don't suggest attribute macros and derives.
+ ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
+ _ => true,
+ }
+ };
+
match qualifier {
- Some(PathQualifierCtx { .. }) => return,
+ Some(PathQualifierCtx { is_infer_qualifier, resolution, .. }) => {
+ if *is_infer_qualifier {
+ ctx.traits_in_scope()
+ .0
+ .into_iter()
+ .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+ .for_each(|item| add_assoc_item(acc, ctx, item));
+ return;
+ }
+ let resolution = match resolution {
+ Some(it) => it,
+ None => return,
+ };
+ // Add associated types on type parameters and `Self`.
+ ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
+ acc.add_type_alias(ctx, alias);
+ None::<()>
+ });
+ match resolution {
+ hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
+ let module_scope = module.scope(ctx.db, Some(ctx.module));
+ for (name, def) in module_scope {
+ if scope_def_applicable(def) {
+ acc.add_resolution(ctx, name, def);
+ }
+ }
+ }
+
+ hir::PathResolution::Def(
+ def @ (hir::ModuleDef::Adt(_)
+ | hir::ModuleDef::TypeAlias(_)
+ | hir::ModuleDef::BuiltinType(_)),
+ ) => {
+ if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
+ add_enum_variants(acc, ctx, e);
+ }
+ let ty = match def {
+ hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
+ hir::ModuleDef::TypeAlias(a) => {
+ let ty = a.ty(ctx.db);
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ cov_mark::hit!(completes_variant_through_alias);
+ add_enum_variants(acc, ctx, e);
+ }
+ ty
+ }
+ hir::ModuleDef::BuiltinType(builtin) => {
+ cov_mark::hit!(completes_primitive_assoc_const);
+ builtin.ty(ctx.db)
+ }
+ _ => unreachable!(),
+ };
+
+ // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
+ // (where AssocType is defined on a trait, not an inherent impl)
+
+ ty.iterate_path_candidates(
+ ctx.db,
+ &ctx.scope,
+ &ctx.traits_in_scope().0,
+ Some(ctx.module),
+ None,
+ |item| {
+ add_assoc_item(acc, ctx, item);
+ None::<()>
+ },
+ );
+
+ // Iterate assoc types separately
+ ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+ if let hir::AssocItem::TypeAlias(ty) = item {
+ acc.add_type_alias(ctx, ty)
+ }
+ None::<()>
+ });
+ }
+ hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
+ // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
+ for item in t.items(ctx.db) {
+ add_assoc_item(acc, ctx, item);
+ }
+ }
+ hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
+ let ty = match resolution {
+ hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+ hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+ _ => return,
+ };
+
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ add_enum_variants(acc, ctx, e);
+ }
+ let mut seen = FxHashSet::default();
+ ty.iterate_path_candidates(
+ ctx.db,
+ &ctx.scope,
+ &ctx.traits_in_scope().0,
+ Some(ctx.module),
+ None,
+ |item| {
+ // We might iterate candidates of a trait multiple times here, so deduplicate
+ // them.
+ if seen.insert(item) {
+ add_assoc_item(acc, ctx, item);
+ }
+ None::<()>
+ },
+ );
+ }
+ _ => (),
+ }
+ }
None if is_absolute_path => acc.add_crate_roots(ctx),
None => {
acc.add_nameref_keywords_with_colon(ctx);
@@ -33,17 +155,22 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
});
}
ctx.process_all_names(&mut |name, def| {
- use hir::{GenericParam::*, ModuleDef::*};
- let add_resolution = match def {
- ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
- // Don't suggest attribute macros and derives.
- ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
- _ => true,
- };
- if add_resolution {
+ if scope_def_applicable(def) {
acc.add_resolution(ctx, name, def);
}
});
}
}
}
+
+fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
+ match item {
+ hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
+ hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
+ hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+ }
+}
+
+fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
+ e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
+}