]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/record.rs
Merge #10841
[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, T};
4
5 use crate::{
6     patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, Completions,
7 };
8
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
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         let module =
63             if let Some(module) = ctx.scope.module() { module } else { strukt.module(ctx.db) };
64
65         let path = module.find_use_path(ctx.db, hir::ModuleDef::from(strukt));
66
67         acc.add_struct_literal(ctx, strukt, path, None);
68     }
69
70     Some(())
71 }
72
73 #[cfg(test)]
74 mod tests {
75     use crate::tests::check_edit;
76
77     #[test]
78     fn literal_struct_completion_edit() {
79         check_edit(
80             "FooDesc {…}",
81             r#"
82 struct FooDesc { pub bar: bool }
83
84 fn create_foo(foo_desc: &FooDesc) -> () { () }
85
86 fn baz() {
87     let foo = create_foo(&$0);
88 }
89             "#,
90             r#"
91 struct FooDesc { pub bar: bool }
92
93 fn create_foo(foo_desc: &FooDesc) -> () { () }
94
95 fn baz() {
96     let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
97 }
98             "#,
99         )
100     }
101
102     #[test]
103     fn literal_struct_completion_from_sub_modules() {
104         check_edit(
105             "Struct {…}",
106             r#"
107 mod submod {
108     pub struct Struct {
109         pub a: u64,
110     }
111 }
112
113 fn f() -> submod::Struct {
114     Stru$0
115 }
116             "#,
117             r#"
118 mod submod {
119     pub struct Struct {
120         pub a: u64,
121     }
122 }
123
124 fn f() -> submod::Struct {
125     submod::Struct { a: ${1:()} }$0
126 }
127             "#,
128         )
129     }
130
131     #[test]
132     fn literal_struct_complexion_module() {
133         check_edit(
134             "FooDesc {…}",
135             r#"
136 mod _69latrick {
137     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
138     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
139 }
140
141 fn baz() {
142     use _69latrick::*;
143
144     let foo = create_foo(&$0);
145 }
146             "#,
147             r#"
148 mod _69latrick {
149     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
150     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
151 }
152
153 fn baz() {
154     use _69latrick::*;
155
156     let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
157 }
158             "#,
159         );
160     }
161
162     #[test]
163     fn default_completion_edit() {
164         check_edit(
165             "..Default::default()",
166             r#"
167 //- minicore: default
168 struct Struct { foo: u32, bar: usize }
169
170 impl Default for Struct {
171     fn default() -> Self {}
172 }
173
174 fn foo() {
175     let other = Struct {
176         foo: 5,
177         .$0
178     };
179 }
180 "#,
181             r#"
182 struct Struct { foo: u32, bar: usize }
183
184 impl Default for Struct {
185     fn default() -> Self {}
186 }
187
188 fn foo() {
189     let other = Struct {
190         foo: 5,
191         ..Default::default()
192     };
193 }
194 "#,
195         );
196         check_edit(
197             "..Default::default()",
198             r#"
199 //- minicore: default
200 struct Struct { foo: u32, bar: usize }
201
202 impl Default for Struct {
203     fn default() -> Self {}
204 }
205
206 fn foo() {
207     let other = Struct {
208         foo: 5,
209         $0
210     };
211 }
212 "#,
213             r#"
214 struct Struct { foo: u32, bar: usize }
215
216 impl Default for Struct {
217     fn default() -> Self {}
218 }
219
220 fn foo() {
221     let other = Struct {
222         foo: 5,
223         ..Default::default()
224     };
225 }
226 "#,
227         );
228         check_edit(
229             "..Default::default()",
230             r#"
231 //- minicore: default
232 struct Struct { foo: u32, bar: usize }
233
234 impl Default for Struct {
235     fn default() -> Self {}
236 }
237
238 fn foo() {
239     let other = Struct {
240         foo: 5,
241         ..$0
242     };
243 }
244 "#,
245             r#"
246 struct Struct { foo: u32, bar: usize }
247
248 impl Default for Struct {
249     fn default() -> Self {}
250 }
251
252 fn foo() {
253     let other = Struct {
254         foo: 5,
255         ..Default::default()
256     };
257 }
258 "#,
259         );
260     }
261 }