]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/pattern.rs
46cef58f011a01688c16425298c765aefcc66e86
[rust.git] / crates / ide_completion / src / completions / pattern.rs
1 //! Completes constats and paths in patterns.
2
3 use crate::{CompletionContext, Completions};
4
5 /// Completes constants and paths in patterns.
6 pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
7     if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_pat_binding) {
8         return;
9     }
10     if ctx.record_pat_syntax.is_some() {
11         return;
12     }
13
14     if !ctx.is_irrefutable_pat_binding {
15         if let Some(ty) = ctx.expected_type.as_ref() {
16             super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| {
17                 acc.add_qualified_variant_pat(ctx, variant, path.clone());
18                 acc.add_qualified_enum_variant(ctx, variant, path);
19             });
20         }
21     }
22
23     // FIXME: ideally, we should look at the type we are matching against and
24     // suggest variants + auto-imports
25     ctx.scope.process_all_names(&mut |name, res| {
26         let add_resolution = match &res {
27             hir::ScopeDef::ModuleDef(def) => match def {
28                 hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
29                     acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone()));
30                     true
31                 }
32                 hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => {
33                     acc.add_variant_pat(ctx, variant.clone(), Some(name.clone()));
34                     true
35                 }
36                 hir::ModuleDef::Adt(hir::Adt::Enum(..))
37                 | hir::ModuleDef::Variant(..)
38                 | hir::ModuleDef::Const(..)
39                 | hir::ModuleDef::Module(..) => !ctx.is_irrefutable_pat_binding,
40                 _ => false,
41             },
42             hir::ScopeDef::MacroDef(_) => true,
43             hir::ScopeDef::ImplSelfType(impl_) => match impl_.target_ty(ctx.db).as_adt() {
44                 Some(hir::Adt::Struct(strukt)) => {
45                     acc.add_struct_pat(ctx, strukt, Some(name.clone()));
46                     true
47                 }
48                 Some(hir::Adt::Enum(_)) => !ctx.is_irrefutable_pat_binding,
49                 _ => true,
50             },
51             _ => false,
52         };
53         if add_resolution {
54             acc.add_resolution(ctx, name.to_string(), &res);
55         }
56     });
57 }
58
59 #[cfg(test)]
60 mod tests {
61     use expect_test::{expect, Expect};
62
63     use crate::{
64         test_utils::{check_edit, completion_list},
65         CompletionKind,
66     };
67
68     fn check(ra_fixture: &str, expect: Expect) {
69         let actual = completion_list(ra_fixture, CompletionKind::Reference);
70         expect.assert_eq(&actual)
71     }
72
73     fn check_snippet(ra_fixture: &str, expect: Expect) {
74         let actual = completion_list(ra_fixture, CompletionKind::Snippet);
75         expect.assert_eq(&actual)
76     }
77
78     #[test]
79     fn completes_enum_variants_and_modules() {
80         check(
81             r#"
82 enum E { X }
83 use self::E::X;
84 const Z: E = E::X;
85 mod m {}
86
87 static FOO: E = E::X;
88 struct Bar { f: u32 }
89
90 fn foo() {
91    match E::X { a$0 }
92 }
93 "#,
94             expect![[r#"
95                 en E
96                 ct Z
97                 st Bar
98                 ev X
99                 md m
100             "#]],
101         );
102     }
103
104     #[test]
105     fn completes_in_simple_macro_call() {
106         check(
107             r#"
108 macro_rules! m { ($e:expr) => { $e } }
109 enum E { X }
110
111 fn foo() {
112    m!(match E::X { a$0 })
113 }
114 "#,
115             expect![[r#"
116                 ev E::X  ()
117                 en E
118                 ma m!(…) macro_rules! m
119             "#]],
120         );
121     }
122
123     #[test]
124     fn completes_in_irrefutable_let() {
125         check(
126             r#"
127 enum E { X }
128 use self::E::X;
129 const Z: E = E::X;
130 mod m {}
131
132 static FOO: E = E::X;
133 struct Bar { f: u32 }
134
135 fn foo() {
136    let a$0
137 }
138 "#,
139             expect![[r#"
140                 st Bar
141             "#]],
142         );
143     }
144
145     #[test]
146     fn completes_in_param() {
147         check(
148             r#"
149 enum E { X }
150
151 static FOO: E = E::X;
152 struct Bar { f: u32 }
153
154 fn foo(a$0) {
155 }
156 "#,
157             expect![[r#"
158                 st Bar
159             "#]],
160         );
161     }
162
163     #[test]
164     fn completes_pat_in_let() {
165         check_snippet(
166             r#"
167 struct Bar { f: u32 }
168
169 fn foo() {
170    let a$0
171 }
172 "#,
173             expect![[r#"
174                 bn Bar Bar { f$1 }$0
175             "#]],
176         );
177     }
178
179     #[test]
180     fn completes_param_pattern() {
181         check_snippet(
182             r#"
183 struct Foo { bar: String, baz: String }
184 struct Bar(String, String);
185 struct Baz;
186 fn outer(a$0) {}
187 "#,
188             expect![[r#"
189                 bn Foo Foo { bar$1, baz$2 }: Foo$0
190                 bn Bar Bar($1, $2): Bar$0
191             "#]],
192         )
193     }
194
195     #[test]
196     fn completes_let_pattern() {
197         check_snippet(
198             r#"
199 struct Foo { bar: String, baz: String }
200 struct Bar(String, String);
201 struct Baz;
202 fn outer() {
203     let a$0
204 }
205 "#,
206             expect![[r#"
207                 bn Foo Foo { bar$1, baz$2 }$0
208                 bn Bar Bar($1, $2)$0
209             "#]],
210         )
211     }
212
213     #[test]
214     fn completes_refutable_pattern() {
215         check_snippet(
216             r#"
217 struct Foo { bar: i32, baz: i32 }
218 struct Bar(String, String);
219 struct Baz;
220 fn outer() {
221     match () {
222         a$0
223     }
224 }
225 "#,
226             expect![[r#"
227                 bn Foo Foo { bar$1, baz$2 }$0
228                 bn Bar Bar($1, $2)$0
229             "#]],
230         )
231     }
232
233     #[test]
234     fn omits_private_fields_pat() {
235         check_snippet(
236             r#"
237 mod foo {
238     pub struct Foo { pub bar: i32, baz: i32 }
239     pub struct Bar(pub String, String);
240     pub struct Invisible(String, String);
241 }
242 use foo::*;
243
244 fn outer() {
245     match () {
246         a$0
247     }
248 }
249 "#,
250             expect![[r#"
251                 bn Foo Foo { bar$1, .. }$0
252                 bn Bar Bar($1, ..)$0
253             "#]],
254         )
255     }
256
257     #[test]
258     fn only_shows_ident_completion() {
259         check_edit(
260             "Foo",
261             r#"
262 struct Foo(i32);
263 fn main() {
264     match Foo(92) {
265         a$0(92) => (),
266     }
267 }
268 "#,
269             r#"
270 struct Foo(i32);
271 fn main() {
272     match Foo(92) {
273         Foo(92) => (),
274     }
275 }
276 "#,
277         );
278     }
279
280     #[test]
281     fn completes_self_pats() {
282         check_snippet(
283             r#"
284 struct Foo(i32);
285 impl Foo {
286     fn foo() {
287         match () {
288             a$0
289         }
290     }
291 }
292     "#,
293             expect![[r#"
294                 bn Self Self($1)$0
295                 bn Foo  Foo($1)$0
296             "#]],
297         )
298     }
299
300     #[test]
301     fn completes_qualified_variant() {
302         check_snippet(
303             r#"
304 enum Foo {
305     Bar { baz: i32 }
306 }
307 impl Foo {
308     fn foo() {
309         match {Foo::Bar { baz: 0 }} {
310             B$0
311         }
312     }
313 }
314     "#,
315             expect![[r#"
316                 bn Self::Bar Self::Bar { baz$1 }$0
317                 bn Foo::Bar  Foo::Bar { baz$1 }$0
318             "#]],
319         )
320     }
321
322     #[test]
323     fn completes_enum_variant_matcharm() {
324         check(
325             r#"
326 enum Foo { Bar, Baz, Quux }
327
328 fn main() {
329     let foo = Foo::Quux;
330     match foo { Qu$0 }
331 }
332 "#,
333             expect![[r#"
334                 ev Foo::Bar  ()
335                 ev Foo::Baz  ()
336                 ev Foo::Quux ()
337                 en Foo
338             "#]],
339         )
340     }
341
342     #[test]
343     fn completes_enum_variant_matcharm_ref() {
344         check(
345             r#"
346 enum Foo { Bar, Baz, Quux }
347
348 fn main() {
349     let foo = Foo::Quux;
350     match &foo { Qu$0 }
351 }
352 "#,
353             expect![[r#"
354                 ev Foo::Bar  ()
355                 ev Foo::Baz  ()
356                 ev Foo::Quux ()
357                 en Foo
358             "#]],
359         )
360     }
361
362     #[test]
363     fn completes_enum_variant_iflet() {
364         check(
365             r#"
366 enum Foo { Bar, Baz, Quux }
367
368 fn main() {
369     let foo = Foo::Quux;
370     if let Qu$0 = foo { }
371 }
372 "#,
373             expect![[r#"
374                 ev Foo::Bar  ()
375                 ev Foo::Baz  ()
376                 ev Foo::Quux ()
377                 en Foo
378             "#]],
379         )
380     }
381
382     #[test]
383     fn completes_enum_variant_impl() {
384         check(
385             r#"
386 enum Foo { Bar, Baz, Quux }
387 impl Foo {
388     fn foo() { match Foo::Bar { Q$0 } }
389 }
390 "#,
391             expect![[r#"
392                 ev Self::Bar  ()
393                 ev Self::Baz  ()
394                 ev Self::Quux ()
395                 ev Foo::Bar   ()
396                 ev Foo::Baz   ()
397                 ev Foo::Quux  ()
398                 sp Self
399                 en Foo
400             "#]],
401         )
402     }
403 }