• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, PatternContext},
7     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
8     CompletionRelevancePostfixMatch, Completions,
9 };
10 
complete_record_pattern_fields( acc: &mut Completions, ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, )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         let ty = ctx.sema.type_of_pat(&ast::Pat::RecordPat(record_pat.clone()));
18         let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
19             Some(hir::Adt::Union(un)) => {
20                 // ctx.sema.record_pat_missing_fields will always return
21                 // an empty Vec on a union literal. This is normally
22                 // reasonable, but here we'd like to present the full list
23                 // of fields if the literal is empty.
24                 let were_fields_specified =
25                     record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some();
26 
27                 match were_fields_specified {
28                     false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
29                     true => return,
30                 }
31             }
32             _ => ctx.sema.record_pattern_missing_fields(record_pat),
33         };
34         complete_fields(acc, ctx, missing_fields);
35     }
36 }
37 
complete_record_expr_fields( acc: &mut Completions, ctx: &CompletionContext<'_>, record_expr: &ast::RecordExpr, &dot_prefix: &bool, )38 pub(crate) fn complete_record_expr_fields(
39     acc: &mut Completions,
40     ctx: &CompletionContext<'_>,
41     record_expr: &ast::RecordExpr,
42     &dot_prefix: &bool,
43 ) {
44     let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
45 
46     let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
47         Some(hir::Adt::Union(un)) => {
48             // ctx.sema.record_literal_missing_fields will always return
49             // an empty Vec on a union literal. This is normally
50             // reasonable, but here we'd like to present the full list
51             // of fields if the literal is empty.
52             let were_fields_specified =
53                 record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
54 
55             match were_fields_specified {
56                 false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
57                 true => return,
58             }
59         }
60         _ => {
61             let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
62 
63             if !missing_fields.is_empty() {
64                 cov_mark::hit!(functional_update_field);
65                 add_default_update(acc, ctx, ty);
66             }
67             if dot_prefix {
68                 cov_mark::hit!(functional_update_one_dot);
69                 let mut item =
70                     CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
71                 item.insert_text(".");
72                 item.add_to(acc, ctx.db);
73                 return;
74             }
75             missing_fields
76         }
77     };
78     complete_fields(acc, ctx, missing_fields);
79 }
80 
add_default_update( acc: &mut Completions, ctx: &CompletionContext<'_>, ty: Option<hir::TypeInfo>, )81 pub(crate) fn add_default_update(
82     acc: &mut Completions,
83     ctx: &CompletionContext<'_>,
84     ty: Option<hir::TypeInfo>,
85 ) {
86     let default_trait = ctx.famous_defs().core_default_Default();
87     let impls_default_trait = default_trait
88         .zip(ty.as_ref())
89         .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
90     if impls_default_trait {
91         // FIXME: This should make use of scope_def like completions so we get all the other goodies
92         // that is we should handle this like actually completing the default function
93         let completion_text = "..Default::default()";
94         let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
95         let completion_text =
96             completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
97         item.insert_text(completion_text).set_relevance(CompletionRelevance {
98             postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
99             ..Default::default()
100         });
101         item.add_to(acc, ctx.db);
102     }
103 }
104 
complete_fields( acc: &mut Completions, ctx: &CompletionContext<'_>, missing_fields: Vec<(hir::Field, hir::Type)>, )105 fn complete_fields(
106     acc: &mut Completions,
107     ctx: &CompletionContext<'_>,
108     missing_fields: Vec<(hir::Field, hir::Type)>,
109 ) {
110     for (field, ty) in missing_fields {
111         acc.add_field(
112             ctx,
113             &DotAccess {
114                 receiver: None,
115                 receiver_ty: None,
116                 kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
117             },
118             None,
119             field,
120             &ty,
121         );
122     }
123 }
124 
125 #[cfg(test)]
126 mod tests {
127     use ide_db::SnippetCap;
128 
129     use crate::{
130         tests::{check_edit, check_edit_with_config, TEST_CONFIG},
131         CompletionConfig,
132     };
133 
134     #[test]
literal_struct_completion_edit()135     fn literal_struct_completion_edit() {
136         check_edit(
137             "FooDesc{}",
138             r#"
139 struct FooDesc { pub bar: bool }
140 
141 fn create_foo(foo_desc: &FooDesc) -> () { () }
142 
143 fn baz() {
144     let foo = create_foo(&$0);
145 }
146             "#,
147             r#"
148 struct FooDesc { pub bar: bool }
149 
150 fn create_foo(foo_desc: &FooDesc) -> () { () }
151 
152 fn baz() {
153     let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
154 }
155             "#,
156         )
157     }
158 
159     #[test]
enum_variant_no_snippets()160     fn enum_variant_no_snippets() {
161         let conf = CompletionConfig { snippet_cap: SnippetCap::new(false), ..TEST_CONFIG };
162         // tuple variant
163         check_edit_with_config(
164             conf.clone(),
165             "Variant()",
166             r#"
167 enum Enum {
168     Variant(usize),
169 }
170 
171 impl Enum {
172     fn new(u: usize) -> Self {
173         Self::Va$0
174     }
175 }
176 "#,
177             r#"
178 enum Enum {
179     Variant(usize),
180 }
181 
182 impl Enum {
183     fn new(u: usize) -> Self {
184         Self::Variant
185     }
186 }
187 "#,
188         );
189 
190         // record variant
191         check_edit_with_config(
192             conf,
193             "Variant{}",
194             r#"
195 enum Enum {
196     Variant{u: usize},
197 }
198 
199 impl Enum {
200     fn new(u: usize) -> Self {
201         Self::Va$0
202     }
203 }
204 "#,
205             r#"
206 enum Enum {
207     Variant{u: usize},
208 }
209 
210 impl Enum {
211     fn new(u: usize) -> Self {
212         Self::Variant
213     }
214 }
215 "#,
216         )
217     }
218 
219     #[test]
literal_struct_impl_self_completion()220     fn literal_struct_impl_self_completion() {
221         check_edit(
222             "Self{}",
223             r#"
224 struct Foo {
225     bar: u64,
226 }
227 
228 impl Foo {
229     fn new() -> Foo {
230         Self$0
231     }
232 }
233             "#,
234             r#"
235 struct Foo {
236     bar: u64,
237 }
238 
239 impl Foo {
240     fn new() -> Foo {
241         Self { bar: ${1:()} }$0
242     }
243 }
244             "#,
245         );
246 
247         check_edit(
248             "Self()",
249             r#"
250 mod submod {
251     pub struct Foo(pub u64);
252 }
253 
254 impl submod::Foo {
255     fn new() -> submod::Foo {
256         Self$0
257     }
258 }
259             "#,
260             r#"
261 mod submod {
262     pub struct Foo(pub u64);
263 }
264 
265 impl submod::Foo {
266     fn new() -> submod::Foo {
267         Self(${1:()})$0
268     }
269 }
270             "#,
271         )
272     }
273 
274     #[test]
literal_struct_completion_from_sub_modules()275     fn literal_struct_completion_from_sub_modules() {
276         check_edit(
277             "submod::Struct{}",
278             r#"
279 mod submod {
280     pub struct Struct {
281         pub a: u64,
282     }
283 }
284 
285 fn f() -> submod::Struct {
286     Stru$0
287 }
288             "#,
289             r#"
290 mod submod {
291     pub struct Struct {
292         pub a: u64,
293     }
294 }
295 
296 fn f() -> submod::Struct {
297     submod::Struct { a: ${1:()} }$0
298 }
299             "#,
300         )
301     }
302 
303     #[test]
literal_struct_complexion_module()304     fn literal_struct_complexion_module() {
305         check_edit(
306             "FooDesc{}",
307             r#"
308 mod _69latrick {
309     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
310     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
311 }
312 
313 fn baz() {
314     use _69latrick::*;
315 
316     let foo = create_foo(&$0);
317 }
318             "#,
319             r#"
320 mod _69latrick {
321     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
322     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
323 }
324 
325 fn baz() {
326     use _69latrick::*;
327 
328     let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
329 }
330             "#,
331         );
332     }
333 
334     #[test]
default_completion_edit()335     fn default_completion_edit() {
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         check_edit(
369             "..Default::default()",
370             r#"
371 //- minicore: default
372 struct Struct { foo: u32, bar: usize }
373 
374 impl Default for Struct {
375     fn default() -> Self {}
376 }
377 
378 fn foo() {
379     let other = Struct {
380         foo: 5,
381         $0
382     };
383 }
384 "#,
385             r#"
386 struct Struct { foo: u32, bar: usize }
387 
388 impl Default for Struct {
389     fn default() -> Self {}
390 }
391 
392 fn foo() {
393     let other = Struct {
394         foo: 5,
395         ..Default::default()
396     };
397 }
398 "#,
399         );
400         check_edit(
401             "..Default::default()",
402             r#"
403 //- minicore: default
404 struct Struct { foo: u32, bar: usize }
405 
406 impl Default for Struct {
407     fn default() -> Self {}
408 }
409 
410 fn foo() {
411     let other = Struct {
412         foo: 5,
413         ..$0
414     };
415 }
416 "#,
417             r#"
418 struct Struct { foo: u32, bar: usize }
419 
420 impl Default for Struct {
421     fn default() -> Self {}
422 }
423 
424 fn foo() {
425     let other = Struct {
426         foo: 5,
427         ..Default::default()
428     };
429 }
430 "#,
431         );
432     }
433 }
434