2021-12-06 15:51:33 +01:00
|
|
|
//! Completes constants and paths in unqualified patterns.
|
2019-09-30 11:58:53 +03:00
|
|
|
|
2022-02-02 18:09:30 +01:00
|
|
|
use hir::{db::DefDatabase, AssocItem, ScopeDef};
|
|
|
|
use rustc_hash::FxHashSet;
|
|
|
|
use syntax::ast::Pat;
|
2021-12-10 18:25:54 +01:00
|
|
|
|
2021-08-14 19:06:35 +02:00
|
|
|
use crate::{
|
2022-02-02 18:09:30 +01:00
|
|
|
context::{PathCompletionCtx, PathQualifierCtx, PatternRefutability},
|
2021-08-14 19:06:35 +02:00
|
|
|
CompletionContext, Completions,
|
|
|
|
};
|
2019-02-24 23:49:47 +03:00
|
|
|
|
2021-12-06 15:51:33 +01:00
|
|
|
/// Completes constants and paths in unqualified patterns.
|
2020-10-25 10:59:15 +03:00
|
|
|
pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
2022-02-02 18:09:30 +01:00
|
|
|
let patctx = match &ctx.pattern_ctx {
|
|
|
|
Some(ctx) => ctx,
|
2021-12-06 15:51:33 +01:00
|
|
|
_ => return,
|
2021-05-26 23:46:00 +02:00
|
|
|
};
|
2022-02-02 18:09:30 +01:00
|
|
|
let refutable = patctx.refutability == PatternRefutability::Refutable;
|
|
|
|
|
|
|
|
if let Some(path_ctx) = &ctx.path_context {
|
|
|
|
pattern_path_completion(acc, ctx, path_ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
match patctx.parent_pat.as_ref() {
|
|
|
|
Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
|
|
|
|
Some(Pat::RefPat(r)) => {
|
|
|
|
if r.mut_token().is_none() {
|
|
|
|
acc.add_keyword(ctx, "mut");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let tok = ctx.token.text_range().start();
|
|
|
|
match (patctx.ref_token.as_ref(), patctx.mut_token.as_ref()) {
|
|
|
|
(None, None) => {
|
|
|
|
acc.add_keyword(ctx, "ref");
|
|
|
|
acc.add_keyword(ctx, "mut");
|
|
|
|
}
|
|
|
|
(None, Some(m)) if tok < m.text_range().start() => {
|
|
|
|
acc.add_keyword(ctx, "ref");
|
|
|
|
}
|
|
|
|
(Some(r), None) if tok > r.text_range().end() => {
|
|
|
|
acc.add_keyword(ctx, "mut");
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-10 18:25:54 +01:00
|
|
|
let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
|
2020-04-11 23:33:17 +02:00
|
|
|
|
2021-12-10 18:25:54 +01:00
|
|
|
if let Some(hir::Adt::Enum(e)) =
|
|
|
|
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
|
|
|
|
{
|
|
|
|
if refutable || single_variant_enum(e) {
|
2021-06-16 17:37:23 +02:00
|
|
|
super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| {
|
2021-03-15 17:23:08 +01:00
|
|
|
acc.add_qualified_variant_pat(ctx, variant, path.clone());
|
|
|
|
acc.add_qualified_enum_variant(ctx, variant, path);
|
|
|
|
});
|
|
|
|
}
|
2021-02-09 21:32:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-23 10:53:48 +03:00
|
|
|
// FIXME: ideally, we should look at the type we are matching against and
|
2019-02-24 23:49:47 +03:00
|
|
|
// suggest variants + auto-imports
|
2021-07-28 15:59:02 +02:00
|
|
|
ctx.process_all_names(&mut |name, res| {
|
2021-12-10 18:25:54 +01:00
|
|
|
let add_resolution = match res {
|
2020-12-20 18:19:23 +01:00
|
|
|
hir::ScopeDef::ModuleDef(def) => match def {
|
|
|
|
hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
|
2021-12-10 18:25:54 +01:00
|
|
|
acc.add_struct_pat(ctx, strukt, Some(name.clone()));
|
2020-12-20 18:19:23 +01:00
|
|
|
true
|
|
|
|
}
|
2021-12-10 18:25:54 +01:00
|
|
|
hir::ModuleDef::Variant(variant)
|
|
|
|
if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
|
|
|
|
{
|
|
|
|
acc.add_variant_pat(ctx, variant, Some(name.clone()));
|
2020-12-20 18:19:23 +01:00
|
|
|
true
|
2020-11-25 23:25:10 +01:00
|
|
|
}
|
2021-12-10 18:25:54 +01:00
|
|
|
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
|
|
|
hir::ModuleDef::Const(..) | hir::ModuleDef::Module(..) => refutable,
|
2020-12-20 18:19:23 +01:00
|
|
|
_ => false,
|
|
|
|
},
|
2021-06-08 17:31:47 +02:00
|
|
|
hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
2021-03-29 17:46:33 +02:00
|
|
|
hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
|
2021-02-09 19:47:21 +01:00
|
|
|
Some(hir::Adt::Struct(strukt)) => {
|
|
|
|
acc.add_struct_pat(ctx, strukt, Some(name.clone()));
|
|
|
|
true
|
|
|
|
}
|
2021-05-26 22:39:47 +02:00
|
|
|
Some(hir::Adt::Enum(_)) => refutable,
|
2021-02-09 19:47:21 +01:00
|
|
|
_ => true,
|
|
|
|
},
|
2020-11-25 23:25:10 +01:00
|
|
|
_ => false,
|
2019-02-24 23:49:47 +03:00
|
|
|
};
|
2020-11-25 23:25:10 +01:00
|
|
|
if add_resolution {
|
2021-12-21 14:07:48 +01:00
|
|
|
acc.add_resolution(ctx, name, res);
|
2020-11-25 23:25:10 +01:00
|
|
|
}
|
2019-09-12 23:35:53 +03:00
|
|
|
});
|
2019-02-24 23:49:47 +03:00
|
|
|
}
|
2022-02-02 18:09:30 +01:00
|
|
|
|
|
|
|
fn pattern_path_completion(
|
|
|
|
acc: &mut Completions,
|
|
|
|
ctx: &CompletionContext,
|
|
|
|
PathCompletionCtx { qualifier, is_absolute_path, .. }: &PathCompletionCtx,
|
|
|
|
) {
|
|
|
|
match qualifier {
|
|
|
|
Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
|
|
|
|
if *is_super_chain {
|
|
|
|
acc.add_keyword(ctx, "super::");
|
|
|
|
}
|
|
|
|
|
|
|
|
let resolution = match resolution {
|
|
|
|
Some(it) => it,
|
|
|
|
None => return,
|
|
|
|
};
|
|
|
|
|
|
|
|
match resolution {
|
|
|
|
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
|
|
|
let module_scope = module.scope(ctx.db, ctx.module);
|
|
|
|
for (name, def) in module_scope {
|
|
|
|
let add_resolution = match def {
|
|
|
|
ScopeDef::MacroDef(m) if m.is_fn_like() => true,
|
|
|
|
ScopeDef::ModuleDef(_) => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if add_resolution {
|
|
|
|
acc.add_resolution(ctx, name, def);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
|
|
|
|
cov_mark::hit!(enum_plain_qualified_use_tree);
|
|
|
|
e.variants(ctx.db)
|
|
|
|
.into_iter()
|
|
|
|
.for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
|
|
|
}
|
|
|
|
res @ (hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_)) => {
|
|
|
|
if let Some(krate) = ctx.krate {
|
|
|
|
let ty = match res {
|
|
|
|
hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
|
|
|
|
hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
|
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Note associated consts cannot be referenced in patterns
|
|
|
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
|
|
|
e.variants(ctx.db)
|
|
|
|
.into_iter()
|
|
|
|
.for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
|
|
|
}
|
|
|
|
|
|
|
|
let traits_in_scope = ctx.scope.visible_traits();
|
|
|
|
let mut seen = FxHashSet::default();
|
|
|
|
ty.iterate_path_candidates(
|
|
|
|
ctx.db,
|
|
|
|
krate,
|
|
|
|
&traits_in_scope,
|
|
|
|
ctx.module,
|
|
|
|
None,
|
|
|
|
|_ty, item| {
|
|
|
|
// We might iterate candidates of a trait multiple times here, so deduplicate
|
|
|
|
// them.
|
|
|
|
if let AssocItem::TypeAlias(ta) = item {
|
|
|
|
if seen.insert(item) {
|
|
|
|
acc.add_type_alias(ctx, ta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None::<()>
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
|
|
|
|
// so executing the rest of this completion doesn't make sense
|
|
|
|
// fresh use tree with leading colon2, only show crate roots
|
|
|
|
None if *is_absolute_path => {
|
|
|
|
cov_mark::hit!(use_tree_crate_roots_only);
|
|
|
|
ctx.process_all_names(&mut |name, res| match res {
|
|
|
|
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
|
|
|
|
acc.add_resolution(ctx, name, res);
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// only show modules in a fresh UseTree
|
|
|
|
None => {
|
|
|
|
cov_mark::hit!(unqualified_path_only_modules_in_import);
|
|
|
|
ctx.process_all_names(&mut |name, res| {
|
|
|
|
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
|
|
|
|
acc.add_resolution(ctx, name, res);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|