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