]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/record.rs
Merge #9845
[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 pub(crate) fn complete_record_literal(
49     acc: &mut Completions,
50     ctx: &CompletionContext,
51 ) -> Option<()> {
52     if !ctx.expects_expression() {
53         return None;
54     }
55
56     if let hir::Adt::Struct(strukt) = ctx.expected_type.as_ref()?.as_adt()? {
57         acc.add_struct_literal(ctx, strukt, None);
58     }
59
60     Some(())
61 }
62
63 #[cfg(test)]
64 mod tests {
65     use crate::tests::check_edit;
66
67     #[test]
68     fn literal_struct_completion_edit() {
69         check_edit(
70             "FooDesc {…}",
71             r#"
72 struct FooDesc { pub bar: bool }
73
74 fn create_foo(foo_desc: &FooDesc) -> () { () }
75
76 fn baz() {
77     let foo = create_foo(&$0);
78 }
79             "#,
80             r#"
81 struct FooDesc { pub bar: bool }
82
83 fn create_foo(foo_desc: &FooDesc) -> () { () }
84
85 fn baz() {
86     let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
87 }
88             "#,
89         )
90     }
91
92     #[test]
93     fn literal_struct_complexion_module() {
94         check_edit(
95             "FooDesc {…}",
96             r#"
97 mod _69latrick {
98     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
99     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
100 }
101
102 fn baz() {
103     use _69latrick::*;
104
105     let foo = create_foo(&$0);
106 }
107             "#,
108             r#"
109 mod _69latrick {
110     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
111     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
112 }
113
114 fn baz() {
115     use _69latrick::*;
116
117     let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
118 }
119             "#,
120         );
121     }
122
123     #[test]
124     fn default_completion_edit() {
125         check_edit(
126             "..Default::default()",
127             r#"
128 //- minicore: default
129 struct Struct { foo: u32, bar: usize }
130
131 impl Default for Struct {
132     fn default() -> Self {}
133 }
134
135 fn foo() {
136     let other = Struct {
137         foo: 5,
138         .$0
139     };
140 }
141 "#,
142             r#"
143 struct Struct { foo: u32, bar: usize }
144
145 impl Default for Struct {
146     fn default() -> Self {}
147 }
148
149 fn foo() {
150     let other = Struct {
151         foo: 5,
152         ..Default::default()
153     };
154 }
155 "#,
156         );
157         check_edit(
158             "..Default::default()",
159             r#"
160 //- minicore: default
161 struct Struct { foo: u32, bar: usize }
162
163 impl Default for Struct {
164     fn default() -> Self {}
165 }
166
167 fn foo() {
168     let other = Struct {
169         foo: 5,
170         $0
171     };
172 }
173 "#,
174             r#"
175 struct Struct { foo: u32, bar: usize }
176
177 impl Default for Struct {
178     fn default() -> Self {}
179 }
180
181 fn foo() {
182     let other = Struct {
183         foo: 5,
184         ..Default::default()
185     };
186 }
187 "#,
188         );
189         check_edit(
190             "..Default::default()",
191             r#"
192 //- minicore: default
193 struct Struct { foo: u32, bar: usize }
194
195 impl Default for Struct {
196     fn default() -> Self {}
197 }
198
199 fn foo() {
200     let other = Struct {
201         foo: 5,
202         ..$0
203     };
204 }
205 "#,
206             r#"
207 struct Struct { foo: u32, bar: usize }
208
209 impl Default for Struct {
210     fn default() -> Self {}
211 }
212
213 fn foo() {
214     let other = Struct {
215         foo: 5,
216         ..Default::default()
217     };
218 }
219 "#,
220         );
221     }
222 }