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