]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/record.rs
Merge #9062
[rust.git] / crates / ide_completion / src / completions / record.rs
1 //! Complete fields in record literals and patterns.
2 use ide_db::{helpers::FamousDefs, SymbolKind};
3 use syntax::ast::Expr;
4
5 use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
6
7 pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
8     let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
9         (None, None) => return None,
10         (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
11         (Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
12         (_, Some(record_lit)) => {
13             let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone()));
14             let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
15             let impl_default_trait = default_trait
16                 .zip(ty)
17                 .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[]));
18
19             let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
20             if impl_default_trait && !missing_fields.is_empty() {
21                 let completion_text = "..Default::default()";
22                 let mut item = CompletionItem::new(
23                     CompletionKind::Snippet,
24                     ctx.source_range(),
25                     completion_text,
26                 );
27                 let completion_text =
28                     completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
29                 item.insert_text(completion_text).kind(SymbolKind::Field);
30                 item.add_to(acc);
31             }
32
33             missing_fields
34         }
35     };
36
37     for (field, ty) in missing_fields {
38         acc.add_field(ctx, field, &ty);
39     }
40
41     Some(())
42 }
43
44 #[cfg(test)]
45 mod tests {
46     use expect_test::{expect, Expect};
47     use ide_db::helpers::FamousDefs;
48
49     use crate::{
50         test_utils::{self, completion_list},
51         CompletionKind,
52     };
53
54     fn check(ra_fixture: &str, expect: Expect) {
55         let actual = completion_list(ra_fixture, CompletionKind::Reference);
56         expect.assert_eq(&actual);
57     }
58
59     fn check_snippet(ra_fixture: &str, expect: Expect) {
60         let actual = completion_list(
61             &format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE),
62             CompletionKind::Snippet,
63         );
64         expect.assert_eq(&actual);
65     }
66
67     fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
68         test_utils::check_edit(
69             what,
70             &format!(
71                 "//- /main.rs crate:main deps:core{}\n{}",
72                 ra_fixture_before,
73                 FamousDefs::FIXTURE,
74             ),
75             &(ra_fixture_after.to_owned() + "\n"),
76         );
77     }
78
79     #[test]
80     fn test_record_literal_field_default() {
81         let test_code = r#"
82 struct S { foo: u32, bar: usize }
83
84 impl core::default::Default for S {
85     fn default() -> Self {
86         S {
87             foo: 0,
88             bar: 0,
89         }
90     }
91 }
92
93 fn process(f: S) {
94     let other = S {
95         foo: 5,
96         .$0
97     };
98 }
99 "#;
100         check(
101             test_code,
102             expect![[r#"
103                 fd bar usize
104             "#]],
105         );
106
107         check_snippet(
108             test_code,
109             expect![[r#"
110                 fd ..Default::default()
111             "#]],
112         );
113     }
114
115     #[test]
116     fn test_record_literal_field_default_completion() {
117         check_edit(
118             "..Default::default()",
119             r#"
120 struct S { foo: u32, bar: usize }
121
122 impl core::default::Default for S {
123     fn default() -> Self {
124         S {
125             foo: 0,
126             bar: 0,
127         }
128     }
129 }
130
131 fn process(f: S) {
132     let other = S {
133         foo: 5,
134         .$0
135     };
136 }
137 "#,
138             r#"
139 struct S { foo: u32, bar: usize }
140
141 impl core::default::Default for S {
142     fn default() -> Self {
143         S {
144             foo: 0,
145             bar: 0,
146         }
147     }
148 }
149
150 fn process(f: S) {
151     let other = S {
152         foo: 5,
153         ..Default::default()
154     };
155 }
156 "#,
157         );
158     }
159
160     #[test]
161     fn test_record_literal_field_without_default() {
162         let test_code = r#"
163 struct S { foo: u32, bar: usize }
164
165 fn process(f: S) {
166     let other = S {
167         foo: 5,
168         .$0
169     };
170 }
171 "#;
172         check(
173             test_code,
174             expect![[r#"
175                 fd bar usize
176             "#]],
177         );
178
179         check_snippet(test_code, expect![[r#""#]]);
180     }
181
182     #[test]
183     fn test_record_pattern_field() {
184         check(
185             r#"
186 struct S { foo: u32 }
187
188 fn process(f: S) {
189     match f {
190         S { f$0: 92 } => (),
191     }
192 }
193 "#,
194             expect![[r#"
195                 fd foo u32
196             "#]],
197         );
198     }
199
200     #[test]
201     fn test_record_pattern_enum_variant() {
202         check(
203             r#"
204 enum E { S { foo: u32, bar: () } }
205
206 fn process(e: E) {
207     match e {
208         E::S { $0 } => (),
209     }
210 }
211 "#,
212             expect![[r#"
213                 fd foo u32
214                 fd bar ()
215             "#]],
216         );
217     }
218
219     #[test]
220     fn test_record_pattern_field_in_simple_macro() {
221         check(
222             r"
223 macro_rules! m { ($e:expr) => { $e } }
224 struct S { foo: u32 }
225
226 fn process(f: S) {
227     m!(match f {
228         S { f$0: 92 } => (),
229     })
230 }
231 ",
232             expect![[r#"
233                 fd foo u32
234             "#]],
235         );
236     }
237
238     #[test]
239     fn only_missing_fields_are_completed_in_destruct_pats() {
240         check(
241             r#"
242 struct S {
243     foo1: u32, foo2: u32,
244     bar: u32, baz: u32,
245 }
246
247 fn main() {
248     let s = S {
249         foo1: 1, foo2: 2,
250         bar: 3, baz: 4,
251     };
252     if let S { foo1, foo2: a, $0 } = s {}
253 }
254 "#,
255             expect![[r#"
256                 fd bar u32
257                 fd baz u32
258             "#]],
259         );
260     }
261
262     #[test]
263     fn test_record_literal_field() {
264         check(
265             r#"
266 struct A { the_field: u32 }
267 fn foo() {
268    A { the$0 }
269 }
270 "#,
271             expect![[r#"
272                 fd the_field u32
273             "#]],
274         );
275     }
276
277     #[test]
278     fn test_record_literal_enum_variant() {
279         check(
280             r#"
281 enum E { A { a: u32 } }
282 fn foo() {
283     let _ = E::A { $0 }
284 }
285 "#,
286             expect![[r#"
287                 fd a u32
288             "#]],
289         );
290     }
291
292     #[test]
293     fn test_record_literal_two_structs() {
294         check(
295             r#"
296 struct A { a: u32 }
297 struct B { b: u32 }
298
299 fn foo() {
300    let _: A = B { $0 }
301 }
302 "#,
303             expect![[r#"
304                 fd b u32
305             "#]],
306         );
307     }
308
309     #[test]
310     fn test_record_literal_generic_struct() {
311         check(
312             r#"
313 struct A<T> { a: T }
314
315 fn foo() {
316    let _: A<u32> = A { $0 }
317 }
318 "#,
319             expect![[r#"
320                 fd a u32
321             "#]],
322         );
323     }
324
325     #[test]
326     fn test_record_literal_field_in_simple_macro() {
327         check(
328             r#"
329 macro_rules! m { ($e:expr) => { $e } }
330 struct A { the_field: u32 }
331 fn foo() {
332    m!(A { the$0 })
333 }
334 "#,
335             expect![[r#"
336                 fd the_field u32
337             "#]],
338         );
339     }
340
341     #[test]
342     fn only_missing_fields_are_completed() {
343         check(
344             r#"
345 struct S {
346     foo1: u32, foo2: u32,
347     bar: u32, baz: u32,
348 }
349
350 fn main() {
351     let foo1 = 1;
352     let s = S { foo1, foo2: 5, $0 }
353 }
354 "#,
355             expect![[r#"
356                 fd bar u32
357                 fd baz u32
358             "#]],
359         );
360     }
361
362     #[test]
363     fn completes_functional_update() {
364         check(
365             r#"
366 struct S { foo1: u32, foo2: u32 }
367
368 fn main() {
369     let foo1 = 1;
370     let s = S { foo1, $0 .. loop {} }
371 }
372 "#,
373             expect![[r#"
374                 fd foo2 u32
375             "#]],
376         );
377     }
378 }