ide_completion/completions/
record.rs1use hir::{HasContainer, ItemContainer};
3use ide_db::SymbolKind;
4use syntax::{
5 SmolStr, T,
6 algo::next_non_trivia_token,
7 ast::{self, Expr},
8};
9
10use crate::{
11 CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
12 CompletionRelevancePostfixMatch, Completions,
13 context::{DotAccess, DotAccessExprCtx, DotAccessKind, PatternContext},
14};
15
16pub(crate) fn complete_record_pattern_fields(
17 acc: &mut Completions,
18 ctx: &CompletionContext<'_, '_>,
19 pattern_ctx: &PatternContext,
20) {
21 if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx {
22 let ty = ctx.sema.type_of_pat(&ast::Pat::RecordPat(record_pat.clone()));
23 let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
24 Some(hir::Adt::Union(un)) => {
25 let were_fields_specified =
30 record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some();
31
32 match were_fields_specified {
33 false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
34 true => return,
35 }
36 }
37 _ => ctx.sema.record_pattern_matched_fields(record_pat),
38 };
39 complete_fields(acc, ctx, missing_fields);
40 }
41}
42
43pub(crate) fn complete_record_expr_fields(
44 acc: &mut Completions,
45 ctx: &CompletionContext<'_, '_>,
46 record_expr: &ast::RecordExpr,
47 &dot_prefix: &bool,
48) {
49 let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
50
51 let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
52 Some(hir::Adt::Union(un)) => {
53 let were_fields_specified =
58 record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
59
60 match were_fields_specified {
61 false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
62 true => return,
63 }
64 }
65 _ => {
66 let suggest_fields = ctx.sema.record_literal_matched_fields(record_expr);
67 let update_exists = record_expr
68 .record_expr_field_list()
69 .is_some_and(|list| list.dotdot_token().is_some());
70
71 if !suggest_fields.is_empty() && !update_exists {
72 cov_mark::hit!(functional_update_field);
73 add_default_update(acc, ctx, ty.as_ref());
74 }
75 if dot_prefix {
76 cov_mark::hit!(functional_update_one_dot);
77 let mut item = CompletionItem::new(
78 CompletionItemKind::Snippet,
79 ctx.source_range(),
80 SmolStr::new_static(".."),
81 ctx.edition,
82 );
83 item.insert_text(".");
84 item.add_to(acc, ctx.db);
85 return;
86 }
87 suggest_fields
88 }
89 };
90 complete_fields(acc, ctx, missing_fields);
91}
92
93pub(crate) fn add_default_update(
94 acc: &mut Completions,
95 ctx: &CompletionContext<'_, '_>,
96 ty: Option<&hir::TypeInfo<'_>>,
97) {
98 let default_trait = ctx.famous_defs().core_default_Default();
99 let impls_default_trait = default_trait
100 .zip(ty)
101 .is_some_and(|(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
102 let in_own_default_impl =
103 ty.zip(ctx.containing_function).is_some_and(|(ty, f)| ty.original == f.ret_type(ctx.db)
104 && matches!(f.container(ctx.db), ItemContainer::Impl(impl_) if impl_.trait_(ctx.db) == default_trait));
105 let ends_of_record_list =
106 next_non_trivia_token(ctx.token.clone()).is_none_or(|it| it.kind() == T!['}']);
107
108 if impls_default_trait && !in_own_default_impl && ends_of_record_list {
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}