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