ide_completion/completions/
pattern.rs1use hir::{AssocItem, ScopeDef};
4use ide_db::syntax_helpers::suggest_name;
5use syntax::ast::Pat;
6
7use crate::{
8 CompletionContext, Completions,
9 context::{PathCompletionCtx, PatternContext, PatternRefutability, Qualified},
10};
11
12pub(crate) fn complete_pattern(
14 acc: &mut Completions,
15 ctx: &CompletionContext<'_>,
16 pattern_ctx: &PatternContext,
17) {
18 let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
19
20 match pattern_ctx.parent_pat.as_ref() {
21 Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
22 Some(Pat::RefPat(r)) => {
23 if r.mut_token().is_none() {
24 add_keyword("mut", "mut $0");
25 }
26 }
27 _ => {
28 let tok = ctx.token.text_range().start();
29 match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
30 (None, None) => {
31 add_keyword("ref", "ref $0");
32 add_keyword("mut", "mut $0");
33 }
34 (None, Some(m)) if tok < m.text_range().start() => {
35 add_keyword("ref", "ref $0");
36 }
37 (Some(r), None) if tok > r.text_range().end() => {
38 add_keyword("mut", "mut $0");
39 }
40 _ => (),
41 }
42 }
43 }
44
45 if pattern_ctx.after_if_expr {
46 add_keyword("else", "else {\n $0\n}");
47 add_keyword("else if", "else if $1 {\n $0\n}");
48 }
49
50 if pattern_ctx.record_pat.is_some() {
51 return;
52 }
53
54 if pattern_ctx.should_suggest_name {
56 let mut name_generator = suggest_name::NameGenerator::default();
57 if let Some(suggested) = ctx
58 .expected_type
59 .as_ref()
60 .map(|ty| ty.strip_references())
61 .and_then(|ty| name_generator.for_type(&ty, ctx.db, ctx.edition))
62 {
63 acc.suggest_name(ctx, &suggested);
64 }
65 }
66
67 let refutable = pattern_ctx.refutability == PatternRefutability::Refutable;
68 let single_variant_enum = |enum_: hir::Enum| enum_.num_variants(ctx.db) == 1;
69
70 if let Some(hir::Adt::Enum(e)) =
71 ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
72 && (refutable || single_variant_enum(e))
73 {
74 super::enum_variants_with_paths(
75 acc,
76 ctx,
77 e,
78 pattern_ctx.impl_or_trait.as_ref().and_then(|it| it.as_ref().left()),
79 |acc, ctx, variant, path| {
80 acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
81 },
82 );
83 }
84
85 ctx.process_all_names(&mut |name, res, _| {
88 let add_simple_path = match res {
89 hir::ScopeDef::ModuleDef(def) => match def {
90 hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
91 acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
92 true
93 }
94 hir::ModuleDef::Variant(variant)
95 if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
96 {
97 acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
98 true
99 }
100 hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
101 hir::ModuleDef::Const(..) => refutable,
102 hir::ModuleDef::Module(..) => true,
103 hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
104 hir::ModuleDef::TypeAlias(_) => true,
105 _ => false,
106 },
107 hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
108 Some(hir::Adt::Struct(strukt)) => {
109 acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
110 true
111 }
112 Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
113 Some(hir::Adt::Union(_)) => true,
114 _ => false,
115 },
116 ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => true,
117 ScopeDef::GenericParam(_)
118 | ScopeDef::AdtSelfType(_)
119 | ScopeDef::Local(_)
120 | ScopeDef::Label(_)
121 | ScopeDef::Unknown => false,
122 };
123 if add_simple_path {
124 acc.add_pattern_resolution(ctx, pattern_ctx, name, res);
125 }
126 });
127}
128
129pub(crate) fn complete_pattern_path(
130 acc: &mut Completions,
131 ctx: &CompletionContext<'_>,
132 path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
133) {
134 match qualified {
135 Qualified::With { resolution: Some(resolution), super_chain_len, .. } => {
136 acc.add_super_keyword(ctx, *super_chain_len);
137
138 match resolution {
139 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
140 let module_scope = module.scope(ctx.db, Some(ctx.module));
141 for (name, def) in module_scope {
142 let add_resolution = match def {
143 ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
144 mac.is_fn_like(ctx.db)
145 }
146 ScopeDef::ModuleDef(_) => true,
147 _ => false,
148 };
149
150 if add_resolution {
151 acc.add_path_resolution(ctx, path_ctx, name, def, vec![]);
152 }
153 }
154 }
155 res => {
156 let ty = match res {
157 hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
158 hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
159 hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(s))) => {
160 s.ty(ctx.db)
161 }
162 hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
163 e.ty(ctx.db)
164 }
165 hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
166 u.ty(ctx.db)
167 }
168 hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => ty.ty(ctx.db),
169 hir::PathResolution::Def(hir::ModuleDef::TypeAlias(ty)) => ty.ty(ctx.db),
170 _ => return,
171 };
172
173 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
174 acc.add_enum_variants(ctx, path_ctx, e);
175 }
176
177 ctx.iterate_path_candidates(&ty, |item| match item {
178 AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
179 AssocItem::Const(c) => acc.add_const(ctx, c),
180 _ => {}
181 });
182 }
183 }
184 }
185 Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
186 Qualified::No => {
187 ctx.process_all_names(&mut |name, res, doc_aliases| {
189 let add_completion = match res {
191 ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
192 ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true,
193 ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true,
194 ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
195 ScopeDef::ImplSelfType(_) => true,
196 _ => false,
197 };
198 if add_completion {
199 acc.add_path_resolution(ctx, path_ctx, name, res, doc_aliases);
200 }
201 });
202
203 acc.add_nameref_keywords_with_colon(ctx);
204 }
205 Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
206 }
207}