diff options
Diffstat (limited to 'crates/ide_completion/src/completions/pattern.rs')
-rw-r--r-- | crates/ide_completion/src/completions/pattern.rs | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs new file mode 100644 index 000000000..9282c3827 --- /dev/null +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -0,0 +1,317 @@ | |||
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 let Some(ty) = &ctx.expected_type { | ||
15 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { | ||
16 | acc.add_qualified_variant_pat(ctx, variant, path) | ||
17 | }); | ||
18 | } | ||
19 | |||
20 | // FIXME: ideally, we should look at the type we are matching against and | ||
21 | // suggest variants + auto-imports | ||
22 | ctx.scope.process_all_names(&mut |name, res| { | ||
23 | let add_resolution = match &res { | ||
24 | hir::ScopeDef::ModuleDef(def) => match def { | ||
25 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { | ||
26 | acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone())); | ||
27 | true | ||
28 | } | ||
29 | hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => { | ||
30 | acc.add_variant_pat(ctx, variant.clone(), Some(name.clone())); | ||
31 | true | ||
32 | } | ||
33 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
34 | | hir::ModuleDef::Variant(..) | ||
35 | | hir::ModuleDef::Const(..) | ||
36 | | hir::ModuleDef::Module(..) => !ctx.is_irrefutable_pat_binding, | ||
37 | _ => false, | ||
38 | }, | ||
39 | hir::ScopeDef::MacroDef(_) => true, | ||
40 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.target_ty(ctx.db).as_adt() { | ||
41 | Some(hir::Adt::Struct(strukt)) => { | ||
42 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); | ||
43 | true | ||
44 | } | ||
45 | Some(hir::Adt::Enum(_)) => !ctx.is_irrefutable_pat_binding, | ||
46 | _ => true, | ||
47 | }, | ||
48 | _ => false, | ||
49 | }; | ||
50 | if add_resolution { | ||
51 | acc.add_resolution(ctx, name.to_string(), &res); | ||
52 | } | ||
53 | }); | ||
54 | } | ||
55 | |||
56 | #[cfg(test)] | ||
57 | mod tests { | ||
58 | use expect_test::{expect, Expect}; | ||
59 | |||
60 | use crate::{ | ||
61 | test_utils::{check_edit, completion_list}, | ||
62 | CompletionKind, | ||
63 | }; | ||
64 | |||
65 | fn check(ra_fixture: &str, expect: Expect) { | ||
66 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | ||
67 | expect.assert_eq(&actual) | ||
68 | } | ||
69 | |||
70 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
71 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
72 | expect.assert_eq(&actual) | ||
73 | } | ||
74 | |||
75 | #[test] | ||
76 | fn completes_enum_variants_and_modules() { | ||
77 | check( | ||
78 | r#" | ||
79 | enum E { X } | ||
80 | use self::E::X; | ||
81 | const Z: E = E::X; | ||
82 | mod m {} | ||
83 | |||
84 | static FOO: E = E::X; | ||
85 | struct Bar { f: u32 } | ||
86 | |||
87 | fn foo() { | ||
88 | match E::X { $0 } | ||
89 | } | ||
90 | "#, | ||
91 | expect![[r#" | ||
92 | en E | ||
93 | ct Z | ||
94 | st Bar | ||
95 | ev X | ||
96 | md m | ||
97 | "#]], | ||
98 | ); | ||
99 | } | ||
100 | |||
101 | #[test] | ||
102 | fn completes_in_simple_macro_call() { | ||
103 | check( | ||
104 | r#" | ||
105 | macro_rules! m { ($e:expr) => { $e } } | ||
106 | enum E { X } | ||
107 | |||
108 | fn foo() { | ||
109 | m!(match E::X { $0 }) | ||
110 | } | ||
111 | "#, | ||
112 | expect![[r#" | ||
113 | en E | ||
114 | ma m!(…) macro_rules! m | ||
115 | "#]], | ||
116 | ); | ||
117 | } | ||
118 | |||
119 | #[test] | ||
120 | fn completes_in_irrefutable_let() { | ||
121 | check( | ||
122 | r#" | ||
123 | enum E { X } | ||
124 | use self::E::X; | ||
125 | const Z: E = E::X; | ||
126 | mod m {} | ||
127 | |||
128 | static FOO: E = E::X; | ||
129 | struct Bar { f: u32 } | ||
130 | |||
131 | fn foo() { | ||
132 | let $0 | ||
133 | } | ||
134 | "#, | ||
135 | expect![[r#" | ||
136 | st Bar | ||
137 | "#]], | ||
138 | ); | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn completes_in_param() { | ||
143 | check( | ||
144 | r#" | ||
145 | enum E { X } | ||
146 | |||
147 | static FOO: E = E::X; | ||
148 | struct Bar { f: u32 } | ||
149 | |||
150 | fn foo($0) { | ||
151 | } | ||
152 | "#, | ||
153 | expect![[r#" | ||
154 | st Bar | ||
155 | "#]], | ||
156 | ); | ||
157 | } | ||
158 | |||
159 | #[test] | ||
160 | fn completes_pat_in_let() { | ||
161 | check_snippet( | ||
162 | r#" | ||
163 | struct Bar { f: u32 } | ||
164 | |||
165 | fn foo() { | ||
166 | let $0 | ||
167 | } | ||
168 | "#, | ||
169 | expect![[r#" | ||
170 | bn Bar Bar { f$1 }$0 | ||
171 | "#]], | ||
172 | ); | ||
173 | } | ||
174 | |||
175 | #[test] | ||
176 | fn completes_param_pattern() { | ||
177 | check_snippet( | ||
178 | r#" | ||
179 | struct Foo { bar: String, baz: String } | ||
180 | struct Bar(String, String); | ||
181 | struct Baz; | ||
182 | fn outer($0) {} | ||
183 | "#, | ||
184 | expect![[r#" | ||
185 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
186 | bn Bar Bar($1, $2): Bar$0 | ||
187 | "#]], | ||
188 | ) | ||
189 | } | ||
190 | |||
191 | #[test] | ||
192 | fn completes_let_pattern() { | ||
193 | check_snippet( | ||
194 | r#" | ||
195 | struct Foo { bar: String, baz: String } | ||
196 | struct Bar(String, String); | ||
197 | struct Baz; | ||
198 | fn outer() { | ||
199 | let $0 | ||
200 | } | ||
201 | "#, | ||
202 | expect![[r#" | ||
203 | bn Foo Foo { bar$1, baz$2 }$0 | ||
204 | bn Bar Bar($1, $2)$0 | ||
205 | "#]], | ||
206 | ) | ||
207 | } | ||
208 | |||
209 | #[test] | ||
210 | fn completes_refutable_pattern() { | ||
211 | check_snippet( | ||
212 | r#" | ||
213 | struct Foo { bar: i32, baz: i32 } | ||
214 | struct Bar(String, String); | ||
215 | struct Baz; | ||
216 | fn outer() { | ||
217 | match () { | ||
218 | $0 | ||
219 | } | ||
220 | } | ||
221 | "#, | ||
222 | expect![[r#" | ||
223 | bn Foo Foo { bar$1, baz$2 }$0 | ||
224 | bn Bar Bar($1, $2)$0 | ||
225 | "#]], | ||
226 | ) | ||
227 | } | ||
228 | |||
229 | #[test] | ||
230 | fn omits_private_fields_pat() { | ||
231 | check_snippet( | ||
232 | r#" | ||
233 | mod foo { | ||
234 | pub struct Foo { pub bar: i32, baz: i32 } | ||
235 | pub struct Bar(pub String, String); | ||
236 | pub struct Invisible(String, String); | ||
237 | } | ||
238 | use foo::*; | ||
239 | |||
240 | fn outer() { | ||
241 | match () { | ||
242 | $0 | ||
243 | } | ||
244 | } | ||
245 | "#, | ||
246 | expect![[r#" | ||
247 | bn Foo Foo { bar$1, .. }$0 | ||
248 | bn Bar Bar($1, ..)$0 | ||
249 | "#]], | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | #[test] | ||
254 | fn only_shows_ident_completion() { | ||
255 | check_edit( | ||
256 | "Foo", | ||
257 | r#" | ||
258 | struct Foo(i32); | ||
259 | fn main() { | ||
260 | match Foo(92) { | ||
261 | $0(92) => (), | ||
262 | } | ||
263 | } | ||
264 | "#, | ||
265 | r#" | ||
266 | struct Foo(i32); | ||
267 | fn main() { | ||
268 | match Foo(92) { | ||
269 | Foo(92) => (), | ||
270 | } | ||
271 | } | ||
272 | "#, | ||
273 | ); | ||
274 | } | ||
275 | |||
276 | #[test] | ||
277 | fn completes_self_pats() { | ||
278 | check_snippet( | ||
279 | r#" | ||
280 | struct Foo(i32); | ||
281 | impl Foo { | ||
282 | fn foo() { | ||
283 | match () { | ||
284 | $0 | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | "#, | ||
289 | expect![[r#" | ||
290 | bn Self Self($1)$0 | ||
291 | bn Foo Foo($1)$0 | ||
292 | "#]], | ||
293 | ) | ||
294 | } | ||
295 | |||
296 | #[test] | ||
297 | fn completes_qualified_variant() { | ||
298 | check_snippet( | ||
299 | r#" | ||
300 | enum Foo { | ||
301 | Bar { baz: i32 } | ||
302 | } | ||
303 | impl Foo { | ||
304 | fn foo() { | ||
305 | match {Foo::Bar { baz: 0 }} { | ||
306 | B$0 | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | "#, | ||
311 | expect![[r#" | ||
312 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
313 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
314 | "#]], | ||
315 | ) | ||
316 | } | ||
317 | } | ||