]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
Rollup merge of #100081 - RalfJung:unused-unsafe-in-unsafe-fn, r=jackh726
[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, PatternContext},
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         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
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);
73                 return;
74             }
75             missing_fields
76         }
77     };
78     complete_fields(acc, ctx, missing_fields);
79 }
80
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);
102     }
103 }
104
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 crate::tests::check_edit;
128
129     #[test]
130     fn literal_struct_completion_edit() {
131         check_edit(
132             "FooDesc {…}",
133             r#"
134 struct FooDesc { pub bar: bool }
135
136 fn create_foo(foo_desc: &FooDesc) -> () { () }
137
138 fn baz() {
139     let foo = create_foo(&$0);
140 }
141             "#,
142             r#"
143 struct FooDesc { pub bar: bool }
144
145 fn create_foo(foo_desc: &FooDesc) -> () { () }
146
147 fn baz() {
148     let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
149 }
150             "#,
151         )
152     }
153
154     #[test]
155     fn literal_struct_impl_self_completion() {
156         check_edit(
157             "Self {…}",
158             r#"
159 struct Foo {
160     bar: u64,
161 }
162
163 impl Foo {
164     fn new() -> Foo {
165         Self$0
166     }
167 }
168             "#,
169             r#"
170 struct Foo {
171     bar: u64,
172 }
173
174 impl Foo {
175     fn new() -> Foo {
176         Self { bar: ${1:()} }$0
177     }
178 }
179             "#,
180         );
181
182         check_edit(
183             "Self(…)",
184             r#"
185 mod submod {
186     pub struct Foo(pub u64);
187 }
188
189 impl submod::Foo {
190     fn new() -> submod::Foo {
191         Self$0
192     }
193 }
194             "#,
195             r#"
196 mod submod {
197     pub struct Foo(pub u64);
198 }
199
200 impl submod::Foo {
201     fn new() -> submod::Foo {
202         Self(${1:()})$0
203     }
204 }
205             "#,
206         )
207     }
208
209     #[test]
210     fn literal_struct_completion_from_sub_modules() {
211         check_edit(
212             "submod::Struct {…}",
213             r#"
214 mod submod {
215     pub struct Struct {
216         pub a: u64,
217     }
218 }
219
220 fn f() -> submod::Struct {
221     Stru$0
222 }
223             "#,
224             r#"
225 mod submod {
226     pub struct Struct {
227         pub a: u64,
228     }
229 }
230
231 fn f() -> submod::Struct {
232     submod::Struct { a: ${1:()} }$0
233 }
234             "#,
235         )
236     }
237
238     #[test]
239     fn literal_struct_complexion_module() {
240         check_edit(
241             "FooDesc {…}",
242             r#"
243 mod _69latrick {
244     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
245     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
246 }
247
248 fn baz() {
249     use _69latrick::*;
250
251     let foo = create_foo(&$0);
252 }
253             "#,
254             r#"
255 mod _69latrick {
256     pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
257     pub fn create_foo(foo_desc: &FooDesc) -> () { () }
258 }
259
260 fn baz() {
261     use _69latrick::*;
262
263     let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
264 }
265             "#,
266         );
267     }
268
269     #[test]
270     fn default_completion_edit() {
271         check_edit(
272             "..Default::default()",
273             r#"
274 //- minicore: default
275 struct Struct { foo: u32, bar: usize }
276
277 impl Default for Struct {
278     fn default() -> Self {}
279 }
280
281 fn foo() {
282     let other = Struct {
283         foo: 5,
284         .$0
285     };
286 }
287 "#,
288             r#"
289 struct Struct { foo: u32, bar: usize }
290
291 impl Default for Struct {
292     fn default() -> Self {}
293 }
294
295 fn foo() {
296     let other = Struct {
297         foo: 5,
298         ..Default::default()
299     };
300 }
301 "#,
302         );
303         check_edit(
304             "..Default::default()",
305             r#"
306 //- minicore: default
307 struct Struct { foo: u32, bar: usize }
308
309 impl Default for Struct {
310     fn default() -> Self {}
311 }
312
313 fn foo() {
314     let other = Struct {
315         foo: 5,
316         $0
317     };
318 }
319 "#,
320             r#"
321 struct Struct { foo: u32, bar: usize }
322
323 impl Default for Struct {
324     fn default() -> Self {}
325 }
326
327 fn foo() {
328     let other = Struct {
329         foo: 5,
330         ..Default::default()
331     };
332 }
333 "#,
334         );
335         check_edit(
336             "..Default::default()",
337             r#"
338 //- minicore: default
339 struct Struct { foo: u32, bar: usize }
340
341 impl Default for Struct {
342     fn default() -> Self {}
343 }
344
345 fn foo() {
346     let other = Struct {
347         foo: 5,
348         ..$0
349     };
350 }
351 "#,
352             r#"
353 struct Struct { foo: u32, bar: usize }
354
355 impl Default for Struct {
356     fn default() -> Self {}
357 }
358
359 fn foo() {
360     let other = Struct {
361         foo: 5,
362         ..Default::default()
363     };
364 }
365 "#,
366         );
367     }
368 }