]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/record.rs
Merge #9765
[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.zip(ty).map_or(false, |(default_trait, ty)| {
16                 ty.original.impls_trait(ctx.db, default_trait, &[])
17             });
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, None, field, &ty);
43     }
44
45     Some(())
46 }
47
48 #[cfg(test)]
49 mod tests {
50     use crate::tests::check_edit;
51
52     #[test]
53     fn default_completion_edit() {
54         check_edit(
55             "..Default::default()",
56             r#"
57 //- minicore: default
58 struct Struct { foo: u32, bar: usize }
59
60 impl Default for Struct {
61     fn default() -> Self {}
62 }
63
64 fn foo() {
65     let other = Struct {
66         foo: 5,
67         .$0
68     };
69 }
70 "#,
71             r#"
72 struct Struct { foo: u32, bar: usize }
73
74 impl Default for Struct {
75     fn default() -> Self {}
76 }
77
78 fn foo() {
79     let other = Struct {
80         foo: 5,
81         ..Default::default()
82     };
83 }
84 "#,
85         );
86         check_edit(
87             "..Default::default()",
88             r#"
89 //- minicore: default
90 struct Struct { foo: u32, bar: usize }
91
92 impl Default for Struct {
93     fn default() -> Self {}
94 }
95
96 fn foo() {
97     let other = Struct {
98         foo: 5,
99         $0
100     };
101 }
102 "#,
103             r#"
104 struct Struct { foo: u32, bar: usize }
105
106 impl Default for Struct {
107     fn default() -> Self {}
108 }
109
110 fn foo() {
111     let other = Struct {
112         foo: 5,
113         ..Default::default()
114     };
115 }
116 "#,
117         );
118     }
119 }