]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
Auto merge of #78802 - faern:simplify-socketaddr, r=joshtriplett
[rust.git] / src / tools / rust-analyzer / crates / ide-completion / src / completions / record.rs
1 //! Complete fields in record literals and patterns.
2 use ide_db::SymbolKind;
3 use syntax::ast::{self, Expr};
4
5 use crate::{
6     context::{DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, PatternContext, Qualified},
7     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
8     CompletionRelevancePostfixMatch, Completions,
9 };
10
11 pub(crate) fn complete_record_pattern_fields(
12     acc: &mut Completions,
13     ctx: &CompletionContext<'_>,
14     pattern_ctx: &PatternContext,
15 ) {
16     if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx {
17         complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
18     }
19 }
20
21 pub(crate) fn complete_record_expr_fields(
22     acc: &mut Completions,
23     ctx: &CompletionContext<'_>,
24     record_expr: &ast::RecordExpr,
25     &dot_prefix: &bool,
26 ) {
27     let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
28
29     let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
30         Some(hir::Adt::Union(un)) => {
31             // ctx.sema.record_literal_missing_fields will always return
32             // an empty Vec on a union literal. This is normally
33             // reasonable, but here we'd like to present the full list
34             // of fields if the literal is empty.
35             let were_fields_specified =
36                 record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
37
38             match were_fields_specified {
39                 false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
40                 true => return,
41             }
42         }
43         _ => {
44             let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
45             add_default_update(acc, ctx, ty, &missing_fields);
46             if dot_prefix {
47                 let mut item =
48                     CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
49                 item.insert_text(".");
50                 item.add_to(acc);
51                 return;
52             }
53             missing_fields
54         }
55     };
56     complete_fields(acc, ctx, missing_fields);
57 }
58
59 // FIXME: This should probably be part of complete_path_expr
60 pub(crate) fn complete_record_expr_func_update(
61     acc: &mut Completions,
62     ctx: &CompletionContext<'_>,
63     path_ctx: &PathCompletionCtx,
64     expr_ctx: &ExprCtx,
65 ) {
66     if !matches!(path_ctx.qualified, Qualified::No) {
67         return;
68     }
69     if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx {
70         let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
71
72         match ty.as_ref().and_then(|t| t.original.as_adt()) {
73             Some(hir::Adt::Union(_)) => (),
74             _ => {
75                 let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
76                 add_default_update(acc, ctx, ty, &missing_fields);
77             }
78         };
79     }
80 }
81
82 fn add_default_update(
83     acc: &mut Completions,
84     ctx: &CompletionContext<'_>,
85     ty: Option<hir::TypeInfo>,
86     missing_fields: &[(hir::Field, hir::Type)],
87 ) {
88     let default_trait = ctx.famous_defs().core_default_Default();
89     let impl_default_trait = default_trait
90         .zip(ty.as_ref())
91         .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
92     if impl_default_trait && !missing_fields.is_empty() {
93         // FIXME: This should make use of scope_def like completions so we get all the other goodies
94         let completion_text = "..Default::default()";
95         let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
96         let completion_text =
97             completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
98         item.insert_text(completion_text).set_relevance(CompletionRelevance {
99             postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
100             ..Default::default()
101         });
102         item.add_to(acc);
103     }
104 }
105
106 fn complete_fields(
107     acc: &mut Completions,
108     ctx: &CompletionContext<'_>,
109     missing_fields: Vec<(hir::Field, hir::Type)>,
110 ) {
111     for (field, ty) in missing_fields {
112         acc.add_field(
113             ctx,
114             &DotAccess {
115                 receiver: None,
116                 receiver_ty: None,
117                 kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
118             },
119             None,
120             field,
121             &ty,
122         );
123     }
124 }
125
126 #[cfg(test)]
127 mod tests {
128     use crate::tests::check_edit;
129
130     #[test]
131     fn literal_struct_completion_edit() {
132         check_edit(
133             "FooDesc {…}",
134             r#"
135 struct FooDesc { pub bar: bool }
136
137 fn create_foo(foo_desc: &FooDesc) -> () { () }
138
139 fn baz() {
140     let foo = create_foo(&$0);
141 }
142             "#,
143             r#"
144 struct FooDesc { pub bar: bool }
145
146 fn create_foo(foo_desc: &FooDesc) -> () { () }
147
148 fn baz() {
149     let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
150 }
151             "#,
152         )
153     }
154
155     #[test]
156     fn literal_struct_impl_self_completion() {
157         check_edit(
158             "Self {…}",
159             r#"
160 struct Foo {
161     bar: u64,
162 }
163
164 impl Foo {
165     fn new() -> Foo {
166         Self$0
167     }
168 }
169             "#,
170             r#"
171 struct Foo {
172     bar: u64,
173 }
174
175 impl Foo {
176     fn new() -> Foo {
177         Self { bar: ${1:()} }$0
178     }
179 }
180             "#,
181         );
182
183         check_edit(
184             "Self(…)",
185             r#"
186 mod submod {
187     pub struct Foo(pub u64);
188 }
189
190 impl submod::Foo {
191     fn new() -> submod::Foo {
192         Self$0
193     }
194 }
195             "#,
196             r#"
197 mod submod {
198     pub struct Foo(pub u64);
199 }
200
201 impl submod::Foo {
202     fn new() -> submod::Foo {
203         Self(${1:()})$0
204     }
205 }
206             "#,
207         )
208     }
209
210     #[test]
211     fn literal_struct_completion_from_sub_modules() {
212         check_edit(
213             "submod::Struct {…}",
214             r#"
215 mod submod {
216     pub struct Struct {
217         pub a: u64,
218     }
219 }
220
221 fn f() -> submod::Struct {
222     Stru$0
223 }
224             "#,
225             r#"
226 mod submod {
227     pub struct Struct {
228         pub a: u64,
229     }
230 }
231
232 fn f() -> submod::Struct {
233     submod::Struct { a: ${1:()} }$0
234 }
235             "#,
236         )
237     }
238
239     #[test]
240     fn literal_struct_complexion_module() {
241         check_edit(
242             "FooDesc {…}",
243             r#"
244 mod _69latrick {
245     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
246     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
247 }
248
249 fn baz() {
250     use _69latrick::*;
251
252     let foo = create_foo(&$0);
253 }
254             "#,
255             r#"
256 mod _69latrick {
257     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
258     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
259 }
260
261 fn baz() {
262     use _69latrick::*;
263
264     let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
265 }
266             "#,
267         );
268     }
269
270     #[test]
271     fn default_completion_edit() {
272         check_edit(
273             "..Default::default()",
274             r#"
275 //- minicore: default
276 struct Struct { foo: u32, bar: usize }
277
278 impl Default for Struct {
279     fn default() -> Self {}
280 }
281
282 fn foo() {
283     let other = Struct {
284         foo: 5,
285         .$0
286     };
287 }
288 "#,
289             r#"
290 struct Struct { foo: u32, bar: usize }
291
292 impl Default for Struct {
293     fn default() -> Self {}
294 }
295
296 fn foo() {
297     let other = Struct {
298         foo: 5,
299         ..Default::default()
300     };
301 }
302 "#,
303         );
304         check_edit(
305             "..Default::default()",
306             r#"
307 //- minicore: default
308 struct Struct { foo: u32, bar: usize }
309
310 impl Default for Struct {
311     fn default() -> Self {}
312 }
313
314 fn foo() {
315     let other = Struct {
316         foo: 5,
317         $0
318     };
319 }
320 "#,
321             r#"
322 struct Struct { foo: u32, bar: usize }
323
324 impl Default for Struct {
325     fn default() -> Self {}
326 }
327
328 fn foo() {
329     let other = Struct {
330         foo: 5,
331         ..Default::default()
332     };
333 }
334 "#,
335         );
336         check_edit(
337             "..Default::default()",
338             r#"
339 //- minicore: default
340 struct Struct { foo: u32, bar: usize }
341
342 impl Default for Struct {
343     fn default() -> Self {}
344 }
345
346 fn foo() {
347     let other = Struct {
348         foo: 5,
349         ..$0
350     };
351 }
352 "#,
353             r#"
354 struct Struct { foo: u32, bar: usize }
355
356 impl Default for Struct {
357     fn default() -> Self {}
358 }
359
360 fn foo() {
361     let other = Struct {
362         foo: 5,
363         ..Default::default()
364     };
365 }
366 "#,
367         );
368     }
369 }