1 //! Complete fields in record literals and patterns.
2 use ide_db::{helpers::FamousDefs, SymbolKind};
3 use syntax::{ast::Expr, T};
4 
5 use crate::{
6     patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, Completions,
7 };
8 
complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()>9 pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
10     let missing_fields = match &ctx.completion_location {
11         Some(
12             ImmediateLocation::RecordExpr(record_expr)
13             | ImmediateLocation::RecordExprUpdate(record_expr),
14         ) => {
15             let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
16             let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
17             let impl_default_trait = default_trait.zip(ty).map_or(false, |(default_trait, ty)| {
18                 ty.original.impls_trait(ctx.db, default_trait, &[])
19             });
20 
21             let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
22             if impl_default_trait && !missing_fields.is_empty() && ctx.path_qual().is_none() {
23                 let completion_text = "..Default::default()";
24                 let mut item =
25                     CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
26                 let completion_text =
27                     completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
28                 item.insert_text(completion_text);
29                 item.add_to(acc);
30             }
31             if ctx.previous_token_is(T![.]) {
32                 let mut item =
33                     CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
34                 item.insert_text(".");
35                 item.add_to(acc);
36                 return None;
37             }
38             missing_fields
39         }
40         Some(ImmediateLocation::RecordPat(record_pat)) => {
41             ctx.sema.record_pattern_missing_fields(record_pat)
42         }
43         _ => return None,
44     };
45 
46     for (field, ty) in missing_fields {
47         acc.add_field(ctx, None, field, &ty);
48     }
49 
50     Some(())
51 }
52 
complete_record_literal( acc: &mut Completions, ctx: &CompletionContext, ) -> Option<()>53 pub(crate) fn complete_record_literal(
54     acc: &mut Completions,
55     ctx: &CompletionContext,
56 ) -> Option<()> {
57     if !ctx.expects_expression() {
58         return None;
59     }
60 
61     if let hir::Adt::Struct(strukt) = ctx.expected_type.as_ref()?.as_adt()? {
62         acc.add_struct_literal(ctx, strukt, None);
63     }
64 
65     Some(())
66 }
67 
68 #[cfg(test)]
69 mod tests {
70     use crate::tests::check_edit;
71 
72     #[test]
literal_struct_completion_edit()73     fn literal_struct_completion_edit() {
74         check_edit(
75             "FooDesc {…}",
76             r#"
77 struct FooDesc { pub bar: bool }
78 
79 fn create_foo(foo_desc: &FooDesc) -> () { () }
80 
81 fn baz() {
82     let foo = create_foo(&$0);
83 }
84             "#,
85             r#"
86 struct FooDesc { pub bar: bool }
87 
88 fn create_foo(foo_desc: &FooDesc) -> () { () }
89 
90 fn baz() {
91     let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
92 }
93             "#,
94         )
95     }
96 
97     #[test]
literal_struct_complexion_module()98     fn literal_struct_complexion_module() {
99         check_edit(
100             "FooDesc {…}",
101             r#"
102 mod _69latrick {
103     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
104     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
105 }
106 
107 fn baz() {
108     use _69latrick::*;
109 
110     let foo = create_foo(&$0);
111 }
112             "#,
113             r#"
114 mod _69latrick {
115     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
116     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
117 }
118 
119 fn baz() {
120     use _69latrick::*;
121 
122     let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
123 }
124             "#,
125         );
126     }
127 
128     #[test]
default_completion_edit()129     fn default_completion_edit() {
130         check_edit(
131             "..Default::default()",
132             r#"
133 //- minicore: default
134 struct Struct { foo: u32, bar: usize }
135 
136 impl Default for Struct {
137     fn default() -> Self {}
138 }
139 
140 fn foo() {
141     let other = Struct {
142         foo: 5,
143         .$0
144     };
145 }
146 "#,
147             r#"
148 struct Struct { foo: u32, bar: usize }
149 
150 impl Default for Struct {
151     fn default() -> Self {}
152 }
153 
154 fn foo() {
155     let other = Struct {
156         foo: 5,
157         ..Default::default()
158     };
159 }
160 "#,
161         );
162         check_edit(
163             "..Default::default()",
164             r#"
165 //- minicore: default
166 struct Struct { foo: u32, bar: usize }
167 
168 impl Default for Struct {
169     fn default() -> Self {}
170 }
171 
172 fn foo() {
173     let other = Struct {
174         foo: 5,
175         $0
176     };
177 }
178 "#,
179             r#"
180 struct Struct { foo: u32, bar: usize }
181 
182 impl Default for Struct {
183     fn default() -> Self {}
184 }
185 
186 fn foo() {
187     let other = Struct {
188         foo: 5,
189         ..Default::default()
190     };
191 }
192 "#,
193         );
194         check_edit(
195             "..Default::default()",
196             r#"
197 //- minicore: default
198 struct Struct { foo: u32, bar: usize }
199 
200 impl Default for Struct {
201     fn default() -> Self {}
202 }
203 
204 fn foo() {
205     let other = Struct {
206         foo: 5,
207         ..$0
208     };
209 }
210 "#,
211             r#"
212 struct Struct { foo: u32, bar: usize }
213 
214 impl Default for Struct {
215     fn default() -> Self {}
216 }
217 
218 fn foo() {
219     let other = Struct {
220         foo: 5,
221         ..Default::default()
222     };
223 }
224 "#,
225         );
226     }
227 }
228