aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions/record.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-02-17 14:53:31 +0000
committerAleksey Kladov <[email protected]>2021-02-17 14:53:31 +0000
commit3db64a400c78bbd2708e67ddc07df1001fff3f29 (patch)
tree5386aab9c452981be09bc3e4362643a34e6e3617 /crates/ide_completion/src/completions/record.rs
parent6334ce866ab095215381c4b72692b20a84d26e96 (diff)
rename completion -> ide_completion
We don't have completion-related PRs in flight, so lets do it
Diffstat (limited to 'crates/ide_completion/src/completions/record.rs')
-rw-r--r--crates/ide_completion/src/completions/record.rs390
1 files changed, 390 insertions, 0 deletions
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
new file mode 100644
index 000000000..0a7927eb8
--- /dev/null
+++ b/crates/ide_completion/src/completions/record.rs
@@ -0,0 +1,390 @@
1//! Complete fields in record literals and patterns.
2use ide_db::{helpers::FamousDefs, SymbolKind};
3use syntax::ast::Expr;
4
5use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
6
7pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
8 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
9 (None, None) => return None,
10 (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
11 (Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
12 (_, Some(record_lit)) => {
13 let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone()));
14 let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
15 let impl_default_trait = default_trait
16 .and_then(|default_trait| ty.map(|ty| ty.impls_trait(ctx.db, default_trait, &[])))
17 .unwrap_or(false);
18
19 let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
20 if impl_default_trait && !missing_fields.is_empty() {
21 let completion_text = "..Default::default()";
22 let completion_text = completion_text
23 .strip_prefix(ctx.token.to_string().as_str())
24 .unwrap_or(completion_text);
25 acc.add(
26 CompletionItem::new(
27 CompletionKind::Snippet,
28 ctx.source_range(),
29 "..Default::default()",
30 )
31 .insert_text(completion_text)
32 .kind(SymbolKind::Field)
33 .build(),
34 );
35 }
36
37 missing_fields
38 }
39 };
40
41 for (field, ty) in missing_fields {
42 acc.add_field(ctx, field, &ty);
43 }
44
45 Some(())
46}
47
48#[cfg(test)]
49mod tests {
50 use expect_test::{expect, Expect};
51 use ide_db::helpers::FamousDefs;
52
53 use crate::{
54 test_utils::{self, completion_list},
55 CompletionKind,
56 };
57
58 fn check(ra_fixture: &str, expect: Expect) {
59 let actual = completion_list(ra_fixture, CompletionKind::Reference);
60 expect.assert_eq(&actual);
61 }
62
63 fn check_snippet(ra_fixture: &str, expect: Expect) {
64 let actual = completion_list(
65 &format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE),
66 CompletionKind::Snippet,
67 );
68 expect.assert_eq(&actual);
69 }
70
71 fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
72 test_utils::check_edit(
73 what,
74 &format!(
75 "//- /main.rs crate:main deps:core{}\n{}",
76 ra_fixture_before,
77 FamousDefs::FIXTURE,
78 ),
79 &(ra_fixture_after.to_owned() + "\n"),
80 );
81 }
82
83 #[test]
84 fn test_record_literal_field_default() {
85 let test_code = r#"
86struct S { foo: u32, bar: usize }
87
88impl core::default::Default for S {
89 fn default() -> Self {
90 S {
91 foo: 0,
92 bar: 0,
93 }
94 }
95}
96
97fn process(f: S) {
98 let other = S {
99 foo: 5,
100 .$0
101 };
102}
103"#;
104 check(
105 test_code,
106 expect![[r#"
107 fd bar usize
108 "#]],
109 );
110
111 check_snippet(
112 test_code,
113 expect![[r#"
114 sn pd
115 sn ppd
116 fd ..Default::default()
117 "#]],
118 );
119 }
120
121 #[test]
122 fn test_record_literal_field_default_completion() {
123 check_edit(
124 "..Default::default()",
125 r#"
126struct S { foo: u32, bar: usize }
127
128impl core::default::Default for S {
129 fn default() -> Self {
130 S {
131 foo: 0,
132 bar: 0,
133 }
134 }
135}
136
137fn process(f: S) {
138 let other = S {
139 foo: 5,
140 .$0
141 };
142}
143"#,
144 r#"
145struct S { foo: u32, bar: usize }
146
147impl core::default::Default for S {
148 fn default() -> Self {
149 S {
150 foo: 0,
151 bar: 0,
152 }
153 }
154}
155
156fn process(f: S) {
157 let other = S {
158 foo: 5,
159 ..Default::default()
160 };
161}
162"#,
163 );
164 }
165
166 #[test]
167 fn test_record_literal_field_without_default() {
168 let test_code = r#"
169struct S { foo: u32, bar: usize }
170
171fn process(f: S) {
172 let other = S {
173 foo: 5,
174 .$0
175 };
176}
177"#;
178 check(
179 test_code,
180 expect![[r#"
181 fd bar usize
182 "#]],
183 );
184
185 check_snippet(
186 test_code,
187 expect![[r#"
188 sn pd
189 sn ppd
190 "#]],
191 );
192 }
193
194 #[test]
195 fn test_record_pattern_field() {
196 check(
197 r#"
198struct S { foo: u32 }
199
200fn process(f: S) {
201 match f {
202 S { f$0: 92 } => (),
203 }
204}
205"#,
206 expect![[r#"
207 fd foo u32
208 "#]],
209 );
210 }
211
212 #[test]
213 fn test_record_pattern_enum_variant() {
214 check(
215 r#"
216enum E { S { foo: u32, bar: () } }
217
218fn process(e: E) {
219 match e {
220 E::S { $0 } => (),
221 }
222}
223"#,
224 expect![[r#"
225 fd foo u32
226 fd bar ()
227 "#]],
228 );
229 }
230
231 #[test]
232 fn test_record_pattern_field_in_simple_macro() {
233 check(
234 r"
235macro_rules! m { ($e:expr) => { $e } }
236struct S { foo: u32 }
237
238fn process(f: S) {
239 m!(match f {
240 S { f$0: 92 } => (),
241 })
242}
243",
244 expect![[r#"
245 fd foo u32
246 "#]],
247 );
248 }
249
250 #[test]
251 fn only_missing_fields_are_completed_in_destruct_pats() {
252 check(
253 r#"
254struct S {
255 foo1: u32, foo2: u32,
256 bar: u32, baz: u32,
257}
258
259fn main() {
260 let s = S {
261 foo1: 1, foo2: 2,
262 bar: 3, baz: 4,
263 };
264 if let S { foo1, foo2: a, $0 } = s {}
265}
266"#,
267 expect![[r#"
268 fd bar u32
269 fd baz u32
270 "#]],
271 );
272 }
273
274 #[test]
275 fn test_record_literal_field() {
276 check(
277 r#"
278struct A { the_field: u32 }
279fn foo() {
280 A { the$0 }
281}
282"#,
283 expect![[r#"
284 fd the_field u32
285 "#]],
286 );
287 }
288
289 #[test]
290 fn test_record_literal_enum_variant() {
291 check(
292 r#"
293enum E { A { a: u32 } }
294fn foo() {
295 let _ = E::A { $0 }
296}
297"#,
298 expect![[r#"
299 fd a u32
300 "#]],
301 );
302 }
303
304 #[test]
305 fn test_record_literal_two_structs() {
306 check(
307 r#"
308struct A { a: u32 }
309struct B { b: u32 }
310
311fn foo() {
312 let _: A = B { $0 }
313}
314"#,
315 expect![[r#"
316 fd b u32
317 "#]],
318 );
319 }
320
321 #[test]
322 fn test_record_literal_generic_struct() {
323 check(
324 r#"
325struct A<T> { a: T }
326
327fn foo() {
328 let _: A<u32> = A { $0 }
329}
330"#,
331 expect![[r#"
332 fd a u32
333 "#]],
334 );
335 }
336
337 #[test]
338 fn test_record_literal_field_in_simple_macro() {
339 check(
340 r#"
341macro_rules! m { ($e:expr) => { $e } }
342struct A { the_field: u32 }
343fn foo() {
344 m!(A { the$0 })
345}
346"#,
347 expect![[r#"
348 fd the_field u32
349 "#]],
350 );
351 }
352
353 #[test]
354 fn only_missing_fields_are_completed() {
355 check(
356 r#"
357struct S {
358 foo1: u32, foo2: u32,
359 bar: u32, baz: u32,
360}
361
362fn main() {
363 let foo1 = 1;
364 let s = S { foo1, foo2: 5, $0 }
365}
366"#,
367 expect![[r#"
368 fd bar u32
369 fd baz u32
370 "#]],
371 );
372 }
373
374 #[test]
375 fn completes_functional_update() {
376 check(
377 r#"
378struct S { foo1: u32, foo2: u32 }
379
380fn main() {
381 let foo1 = 1;
382 let s = S { foo1, $0 .. loop {} }
383}
384"#,
385 expect![[r#"
386 fd foo2 u32
387 "#]],
388 );
389 }
390}