ide_completion/completions/
record.rs1use ide_db::SymbolKind;
3use syntax::{
4 SmolStr,
5 ast::{self, Expr},
6};
7
8use crate::{
9 CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
10 CompletionRelevancePostfixMatch, Completions,
11 context::{DotAccess, DotAccessExprCtx, DotAccessKind, PatternContext},
12};
13
14pub(crate) fn complete_record_pattern_fields(
15 acc: &mut Completions,
16 ctx: &CompletionContext<'_>,
17 pattern_ctx: &PatternContext,
18) {
19 if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx {
20 let ty = ctx.sema.type_of_pat(&ast::Pat::RecordPat(record_pat.clone()));
21 let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
22 Some(hir::Adt::Union(un)) => {
23 let were_fields_specified =
28 record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some();
29
30 match were_fields_specified {
31 false => un
32 .fields(ctx.db)
33 .into_iter()
34 .map(|f| (f, f.ty(ctx.db).to_type(ctx.db)))
35 .collect(),
36 true => return,
37 }
38 }
39 _ => ctx.sema.record_pattern_missing_fields(record_pat),
40 };
41 complete_fields(acc, ctx, missing_fields);
42 }
43}
44
45pub(crate) fn complete_record_expr_fields(
46 acc: &mut Completions,
47 ctx: &CompletionContext<'_>,
48 record_expr: &ast::RecordExpr,
49 &dot_prefix: &bool,
50) {
51 let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
52
53 let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
54 Some(hir::Adt::Union(un)) => {
55 let were_fields_specified =
60 record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
61
62 match were_fields_specified {
63 false => un
64 .fields(ctx.db)
65 .into_iter()
66 .map(|f| (f, f.ty(ctx.db).to_type(ctx.db)))
67 .collect(),
68 true => return,
69 }
70 }
71 _ => {
72 let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
73 let update_exists = record_expr
74 .record_expr_field_list()
75 .is_some_and(|list| list.dotdot_token().is_some());
76
77 if !missing_fields.is_empty() && !update_exists {
78 cov_mark::hit!(functional_update_field);
79 add_default_update(acc, ctx, ty);
80 }
81 if dot_prefix {
82 cov_mark::hit!(functional_update_one_dot);
83 let mut item = CompletionItem::new(
84 CompletionItemKind::Snippet,
85 ctx.source_range(),
86 SmolStr::new_static(".."),
87 ctx.edition,
88 );
89 item.insert_text(".");
90 item.add_to(acc, ctx.db);
91 return;
92 }
93 missing_fields
94 }
95 };
96 complete_fields(acc, ctx, missing_fields);
97}
98
99pub(crate) fn add_default_update(
100 acc: &mut Completions,
101 ctx: &CompletionContext<'_>,
102 ty: Option<hir::TypeInfo<'_>>,
103) {
104 let default_trait = ctx.famous_defs().core_default_Default();
105 let impls_default_trait = default_trait
106 .zip(ty.as_ref())
107 .is_some_and(|(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
108 if impls_default_trait {
109 let completion_text = "..Default::default()";
112 let mut item = CompletionItem::new(
113 SymbolKind::Field,
114 ctx.source_range(),
115 SmolStr::new_static(completion_text),
116 ctx.edition,
117 );
118 let completion_text =
119 completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
120 item.insert_text(completion_text).set_relevance(CompletionRelevance {
121 postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
122 ..Default::default()
123 });
124 item.add_to(acc, ctx.db);
125 }
126}
127
128fn complete_fields(
129 acc: &mut Completions,
130 ctx: &CompletionContext<'_>,
131 missing_fields: Vec<(hir::Field, hir::Type<'_>)>,
132) {
133 for (field, ty) in missing_fields {
134 acc.add_field(
136 ctx,
137 &DotAccess {
138 receiver: None,
139 receiver_ty: None,
140 kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
141 ctx: DotAccessExprCtx { in_block_expr: false, in_breakable: None },
142 },
143 None,
144 field,
145 &ty,
146 );
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use ide_db::SnippetCap;
153
154 use crate::{
155 CompletionConfig,
156 tests::{TEST_CONFIG, check_edit, check_edit_with_config},
157 };
158
159 #[test]
160 fn literal_struct_completion_edit() {
161 check_edit(
162 "FooDesc{}",
163 r#"
164struct FooDesc { pub bar: bool }
165
166fn create_foo(foo_desc: &FooDesc) -> () { () }
167
168fn baz() {
169 let foo = create_foo(&$0);
170}
171 "#,
172 r#"
173struct FooDesc { pub bar: bool }
174
175fn create_foo(foo_desc: &FooDesc) -> () { () }
176
177fn baz() {
178 let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
179}
180 "#,
181 )
182 }
183
184 #[test]
185 fn literal_struct_completion_shorthand() {
186 check_edit(
187 "FooDesc{}",
188 r#"
189struct FooDesc { pub bar: bool, n: i32 }
190
191fn create_foo(foo_desc: &FooDesc) -> () { () }
192
193fn baz() {
194 let bar = true;
195 let foo = create_foo(&$0);
196}
197 "#,
198 r#"
199struct FooDesc { pub bar: bool, n: i32 }
200
201fn create_foo(foo_desc: &FooDesc) -> () { () }
202
203fn baz() {
204 let bar = true;
205 let foo = create_foo(&FooDesc { bar$1, n: ${2:()} }$0);
206}
207 "#,
208 )
209 }
210
211 #[test]
212 fn enum_variant_no_snippets() {
213 let conf = CompletionConfig { snippet_cap: SnippetCap::new(false), ..TEST_CONFIG };
214 check_edit_with_config(
216 conf.clone(),
217 "Variant()",
218 r#"
219enum Enum {
220 Variant(usize),
221}
222
223impl Enum {
224 fn new(u: usize) -> Self {
225 Self::Va$0
226 }
227}
228"#,
229 r#"
230enum Enum {
231 Variant(usize),
232}
233
234impl Enum {
235 fn new(u: usize) -> Self {
236 Self::Variant
237 }
238}
239"#,
240 );
241
242 check_edit_with_config(
244 conf,
245 "Variant{}",
246 r#"
247enum Enum {
248 Variant{u: usize},
249}
250
251impl Enum {
252 fn new(u: usize) -> Self {
253 Self::Va$0
254 }
255}
256"#,
257 r#"
258enum Enum {
259 Variant{u: usize},
260}
261
262impl Enum {
263 fn new(u: usize) -> Self {
264 Self::Variant
265 }
266}
267"#,
268 )
269 }
270
271 #[test]
272 fn literal_struct_impl_self_completion() {
273 check_edit(
274 "Self{}",
275 r#"
276struct Foo {
277 bar: u64,
278}
279
280impl Foo {
281 fn new() -> Foo {
282 Self$0
283 }
284}
285 "#,
286 r#"
287struct Foo {
288 bar: u64,
289}
290
291impl Foo {
292 fn new() -> Foo {
293 Self { bar: ${1:()} }$0
294 }
295}
296 "#,
297 );
298
299 check_edit(
300 "Self()",
301 r#"
302mod submod {
303 pub struct Foo(pub u64);
304}
305
306impl submod::Foo {
307 fn new() -> submod::Foo {
308 Self$0
309 }
310}
311 "#,
312 r#"
313mod submod {
314 pub struct Foo(pub u64);
315}
316
317impl submod::Foo {
318 fn new() -> submod::Foo {
319 Self(${1:()})$0
320 }
321}
322 "#,
323 )
324 }
325
326 #[test]
327 fn literal_struct_completion_from_sub_modules() {
328 check_edit(
329 "submod::Struct{}",
330 r#"
331mod submod {
332 pub struct Struct {
333 pub a: u64,
334 }
335}
336
337fn f() -> submod::Struct {
338 Stru$0
339}
340 "#,
341 r#"
342mod submod {
343 pub struct Struct {
344 pub a: u64,
345 }
346}
347
348fn f() -> submod::Struct {
349 submod::Struct { a: ${1:()} }$0
350}
351 "#,
352 )
353 }
354
355 #[test]
356 fn literal_struct_complexion_module() {
357 check_edit(
358 "FooDesc{}",
359 r#"
360mod _69latrick {
361 pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
362 pub fn create_foo(foo_desc: &FooDesc) -> () { () }
363}
364
365fn baz() {
366 use _69latrick::*;
367
368 let foo = create_foo(&$0);
369}
370 "#,
371 r#"
372mod _69latrick {
373 pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
374 pub fn create_foo(foo_desc: &FooDesc) -> () { () }
375}
376
377fn baz() {
378 use _69latrick::*;
379
380 let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
381}
382 "#,
383 );
384 }
385
386 #[test]
387 fn default_completion_edit() {
388 check_edit(
389 "..Default::default()",
390 r#"
391//- minicore: default
392struct Struct { foo: u32, bar: usize }
393
394impl Default for Struct {
395 fn default() -> Self {}
396}
397
398fn foo() {
399 let other = Struct {
400 foo: 5,
401 .$0
402 };
403}
404"#,
405 r#"
406struct Struct { foo: u32, bar: usize }
407
408impl Default for Struct {
409 fn default() -> Self {}
410}
411
412fn foo() {
413 let other = Struct {
414 foo: 5,
415 ..Default::default()
416 };
417}
418"#,
419 );
420 check_edit(
421 "..Default::default()",
422 r#"
423//- minicore: default
424struct Struct { foo: u32, bar: usize }
425
426impl Default for Struct {
427 fn default() -> Self {}
428}
429
430fn foo() {
431 let other = Struct {
432 foo: 5,
433 $0
434 };
435}
436"#,
437 r#"
438struct Struct { foo: u32, bar: usize }
439
440impl Default for Struct {
441 fn default() -> Self {}
442}
443
444fn foo() {
445 let other = Struct {
446 foo: 5,
447 ..Default::default()
448 };
449}
450"#,
451 );
452 check_edit(
453 "..Default::default()",
454 r#"
455//- minicore: default
456struct Struct { foo: u32, bar: usize }
457
458impl Default for Struct {
459 fn default() -> Self {}
460}
461
462fn foo() {
463 let other = Struct {
464 foo: 5,
465 ..$0
466 };
467}
468"#,
469 r#"
470struct Struct { foo: u32, bar: usize }
471
472impl Default for Struct {
473 fn default() -> Self {}
474}
475
476fn foo() {
477 let other = Struct {
478 foo: 5,
479 ..Default::default()
480 };
481}
482"#,
483 );
484 }
485
486 #[test]
487 fn callable_field_struct_init() {
488 check_edit(
489 "field",
490 r#"
491struct S {
492 field: fn(),
493}
494
495fn main() {
496 S {fi$0
497}
498"#,
499 r#"
500struct S {
501 field: fn(),
502}
503
504fn main() {
505 S {field
506}
507"#,
508 );
509 }
510}