diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/completion.rs | 16 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_postfix.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_record.rs | 411 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_record_literal.rs | 241 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_record_pattern.rs | 118 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/test_utils.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 101 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 17 | ||||
-rw-r--r-- | crates/ra_ide/src/ssr.rs | 116 |
11 files changed, 590 insertions, 458 deletions
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index cd0757be5..93157bbba 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs | |||
@@ -5,8 +5,7 @@ mod completion_context; | |||
5 | mod presentation; | 5 | mod presentation; |
6 | 6 | ||
7 | mod complete_dot; | 7 | mod complete_dot; |
8 | mod complete_record_literal; | 8 | mod complete_record; |
9 | mod complete_record_pattern; | ||
10 | mod complete_pattern; | 9 | mod complete_pattern; |
11 | mod complete_fn_param; | 10 | mod complete_fn_param; |
12 | mod complete_keyword; | 11 | mod complete_keyword; |
@@ -34,15 +33,15 @@ pub use crate::completion::completion_item::{ | |||
34 | }; | 33 | }; |
35 | 34 | ||
36 | #[derive(Clone, Debug, PartialEq, Eq)] | 35 | #[derive(Clone, Debug, PartialEq, Eq)] |
37 | pub struct CompletionOptions { | 36 | pub struct CompletionConfig { |
38 | pub enable_postfix_completions: bool, | 37 | pub enable_postfix_completions: bool, |
39 | pub add_call_parenthesis: bool, | 38 | pub add_call_parenthesis: bool, |
40 | pub add_call_argument_snippets: bool, | 39 | pub add_call_argument_snippets: bool, |
41 | } | 40 | } |
42 | 41 | ||
43 | impl Default for CompletionOptions { | 42 | impl Default for CompletionConfig { |
44 | fn default() -> Self { | 43 | fn default() -> Self { |
45 | CompletionOptions { | 44 | CompletionConfig { |
46 | enable_postfix_completions: true, | 45 | enable_postfix_completions: true, |
47 | add_call_parenthesis: true, | 46 | add_call_parenthesis: true, |
48 | add_call_argument_snippets: true, | 47 | add_call_argument_snippets: true, |
@@ -75,9 +74,9 @@ impl Default for CompletionOptions { | |||
75 | pub(crate) fn completions( | 74 | pub(crate) fn completions( |
76 | db: &RootDatabase, | 75 | db: &RootDatabase, |
77 | position: FilePosition, | 76 | position: FilePosition, |
78 | options: &CompletionOptions, | 77 | config: &CompletionConfig, |
79 | ) -> Option<Completions> { | 78 | ) -> Option<Completions> { |
80 | let ctx = CompletionContext::new(db, position, options)?; | 79 | let ctx = CompletionContext::new(db, position, config)?; |
81 | 80 | ||
82 | let mut acc = Completions::default(); | 81 | let mut acc = Completions::default(); |
83 | 82 | ||
@@ -89,8 +88,7 @@ pub(crate) fn completions( | |||
89 | complete_path::complete_path(&mut acc, &ctx); | 88 | complete_path::complete_path(&mut acc, &ctx); |
90 | complete_scope::complete_scope(&mut acc, &ctx); | 89 | complete_scope::complete_scope(&mut acc, &ctx); |
91 | complete_dot::complete_dot(&mut acc, &ctx); | 90 | complete_dot::complete_dot(&mut acc, &ctx); |
92 | complete_record_literal::complete_record_literal(&mut acc, &ctx); | 91 | complete_record::complete_record(&mut acc, &ctx); |
93 | complete_record_pattern::complete_record_pattern(&mut acc, &ctx); | ||
94 | complete_pattern::complete_pattern(&mut acc, &ctx); | 92 | complete_pattern::complete_pattern(&mut acc, &ctx); |
95 | complete_postfix::complete_postfix(&mut acc, &ctx); | 93 | complete_postfix::complete_postfix(&mut acc, &ctx); |
96 | complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); | 94 | complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 0a00054b2..29c2881c6 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | 17 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
18 | if !ctx.options.enable_postfix_completions { | 18 | if !ctx.config.enable_postfix_completions { |
19 | return; | 19 | return; |
20 | } | 20 | } |
21 | 21 | ||
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs new file mode 100644 index 000000000..01dd8c6db --- /dev/null +++ b/crates/ra_ide/src/completion/complete_record.rs | |||
@@ -0,0 +1,411 @@ | |||
1 | //! Complete fields in record literals and patterns. | ||
2 | use crate::completion::{CompletionContext, Completions}; | ||
3 | use ra_syntax::{ast, ast::NameOwner, SmolStr}; | ||
4 | |||
5 | pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
6 | let (ty, variant, already_present_fields) = | ||
7 | match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) { | ||
8 | (None, None) => return None, | ||
9 | (Some(_), Some(_)) => panic!("A record cannot be both a literal and a pattern"), | ||
10 | (Some(record_pat), _) => ( | ||
11 | ctx.sema.type_of_pat(&record_pat.clone().into())?, | ||
12 | ctx.sema.resolve_record_pattern(record_pat)?, | ||
13 | pattern_ascribed_fields(record_pat), | ||
14 | ), | ||
15 | (_, Some(record_lit)) => ( | ||
16 | ctx.sema.type_of_expr(&record_lit.clone().into())?, | ||
17 | ctx.sema.resolve_record_literal(record_lit)?, | ||
18 | literal_ascribed_fields(record_lit), | ||
19 | ), | ||
20 | }; | ||
21 | |||
22 | for (field, field_ty) in ty.variant_fields(ctx.db, variant).into_iter().filter(|(field, _)| { | ||
23 | // FIXME: already_present_names better be `Vec<hir::Name>` | ||
24 | !already_present_fields.contains(&SmolStr::from(field.name(ctx.db).to_string())) | ||
25 | }) { | ||
26 | acc.add_field(ctx, field, &field_ty); | ||
27 | } | ||
28 | Some(()) | ||
29 | } | ||
30 | |||
31 | fn literal_ascribed_fields(record_lit: &ast::RecordLit) -> Vec<SmolStr> { | ||
32 | record_lit | ||
33 | .record_field_list() | ||
34 | .map(|field_list| field_list.fields()) | ||
35 | .map(|fields| { | ||
36 | fields | ||
37 | .into_iter() | ||
38 | .filter_map(|field| field.name_ref()) | ||
39 | .map(|name_ref| name_ref.text().clone()) | ||
40 | .collect() | ||
41 | }) | ||
42 | .unwrap_or_default() | ||
43 | } | ||
44 | |||
45 | fn pattern_ascribed_fields(record_pat: &ast::RecordPat) -> Vec<SmolStr> { | ||
46 | record_pat | ||
47 | .record_field_pat_list() | ||
48 | .map(|pat_list| { | ||
49 | pat_list | ||
50 | .record_field_pats() | ||
51 | .filter_map(|fild_pat| fild_pat.name()) | ||
52 | .chain(pat_list.bind_pats().filter_map(|bind_pat| bind_pat.name())) | ||
53 | .map(|name| name.text().clone()) | ||
54 | .collect() | ||
55 | }) | ||
56 | .unwrap_or_default() | ||
57 | } | ||
58 | |||
59 | #[cfg(test)] | ||
60 | mod tests { | ||
61 | mod record_lit_tests { | ||
62 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
63 | use insta::assert_debug_snapshot; | ||
64 | |||
65 | fn complete(code: &str) -> Vec<CompletionItem> { | ||
66 | do_completion(code, CompletionKind::Reference) | ||
67 | } | ||
68 | |||
69 | #[test] | ||
70 | fn test_record_pattern_field() { | ||
71 | let completions = complete( | ||
72 | r" | ||
73 | struct S { foo: u32 } | ||
74 | |||
75 | fn process(f: S) { | ||
76 | match f { | ||
77 | S { f<|>: 92 } => (), | ||
78 | } | ||
79 | } | ||
80 | ", | ||
81 | ); | ||
82 | assert_debug_snapshot!(completions, @r###" | ||
83 | [ | ||
84 | CompletionItem { | ||
85 | label: "foo", | ||
86 | source_range: [117; 118), | ||
87 | delete: [117; 118), | ||
88 | insert: "foo", | ||
89 | kind: Field, | ||
90 | detail: "u32", | ||
91 | }, | ||
92 | ] | ||
93 | "###); | ||
94 | } | ||
95 | |||
96 | #[test] | ||
97 | fn test_record_pattern_enum_variant() { | ||
98 | let completions = complete( | ||
99 | r" | ||
100 | enum E { | ||
101 | S { foo: u32, bar: () } | ||
102 | } | ||
103 | |||
104 | fn process(e: E) { | ||
105 | match e { | ||
106 | E::S { <|> } => (), | ||
107 | } | ||
108 | } | ||
109 | ", | ||
110 | ); | ||
111 | assert_debug_snapshot!(completions, @r###" | ||
112 | [ | ||
113 | CompletionItem { | ||
114 | label: "bar", | ||
115 | source_range: [161; 161), | ||
116 | delete: [161; 161), | ||
117 | insert: "bar", | ||
118 | kind: Field, | ||
119 | detail: "()", | ||
120 | }, | ||
121 | CompletionItem { | ||
122 | label: "foo", | ||
123 | source_range: [161; 161), | ||
124 | delete: [161; 161), | ||
125 | insert: "foo", | ||
126 | kind: Field, | ||
127 | detail: "u32", | ||
128 | }, | ||
129 | ] | ||
130 | "###); | ||
131 | } | ||
132 | |||
133 | #[test] | ||
134 | fn test_record_pattern_field_in_simple_macro() { | ||
135 | let completions = complete( | ||
136 | r" | ||
137 | macro_rules! m { ($e:expr) => { $e } } | ||
138 | struct S { foo: u32 } | ||
139 | |||
140 | fn process(f: S) { | ||
141 | m!(match f { | ||
142 | S { f<|>: 92 } => (), | ||
143 | }) | ||
144 | } | ||
145 | ", | ||
146 | ); | ||
147 | assert_debug_snapshot!(completions, @r###" | ||
148 | [ | ||
149 | CompletionItem { | ||
150 | label: "foo", | ||
151 | source_range: [171; 172), | ||
152 | delete: [171; 172), | ||
153 | insert: "foo", | ||
154 | kind: Field, | ||
155 | detail: "u32", | ||
156 | }, | ||
157 | ] | ||
158 | "###); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn only_missing_fields_are_completed_in_destruct_pats() { | ||
163 | let completions = complete( | ||
164 | r" | ||
165 | struct S { | ||
166 | foo1: u32, | ||
167 | foo2: u32, | ||
168 | bar: u32, | ||
169 | baz: u32, | ||
170 | } | ||
171 | |||
172 | fn main() { | ||
173 | let s = S { | ||
174 | foo1: 1, | ||
175 | foo2: 2, | ||
176 | bar: 3, | ||
177 | baz: 4, | ||
178 | }; | ||
179 | if let S { foo1, foo2: a, <|> } = s {} | ||
180 | } | ||
181 | ", | ||
182 | ); | ||
183 | assert_debug_snapshot!(completions, @r###" | ||
184 | [ | ||
185 | CompletionItem { | ||
186 | label: "bar", | ||
187 | source_range: [372; 372), | ||
188 | delete: [372; 372), | ||
189 | insert: "bar", | ||
190 | kind: Field, | ||
191 | detail: "u32", | ||
192 | }, | ||
193 | CompletionItem { | ||
194 | label: "baz", | ||
195 | source_range: [372; 372), | ||
196 | delete: [372; 372), | ||
197 | insert: "baz", | ||
198 | kind: Field, | ||
199 | detail: "u32", | ||
200 | }, | ||
201 | ] | ||
202 | "###); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | mod record_pat_tests { | ||
207 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
208 | use insta::assert_debug_snapshot; | ||
209 | |||
210 | fn complete(code: &str) -> Vec<CompletionItem> { | ||
211 | do_completion(code, CompletionKind::Reference) | ||
212 | } | ||
213 | |||
214 | #[test] | ||
215 | fn test_record_literal_deprecated_field() { | ||
216 | let completions = complete( | ||
217 | r" | ||
218 | struct A { | ||
219 | #[deprecated] | ||
220 | the_field: u32, | ||
221 | } | ||
222 | fn foo() { | ||
223 | A { the<|> } | ||
224 | } | ||
225 | ", | ||
226 | ); | ||
227 | assert_debug_snapshot!(completions, @r###" | ||
228 | [ | ||
229 | CompletionItem { | ||
230 | label: "the_field", | ||
231 | source_range: [142; 145), | ||
232 | delete: [142; 145), | ||
233 | insert: "the_field", | ||
234 | kind: Field, | ||
235 | detail: "u32", | ||
236 | deprecated: true, | ||
237 | }, | ||
238 | ] | ||
239 | "###); | ||
240 | } | ||
241 | |||
242 | #[test] | ||
243 | fn test_record_literal_field() { | ||
244 | let completions = complete( | ||
245 | r" | ||
246 | struct A { the_field: u32 } | ||
247 | fn foo() { | ||
248 | A { the<|> } | ||
249 | } | ||
250 | ", | ||
251 | ); | ||
252 | assert_debug_snapshot!(completions, @r###" | ||
253 | [ | ||
254 | CompletionItem { | ||
255 | label: "the_field", | ||
256 | source_range: [83; 86), | ||
257 | delete: [83; 86), | ||
258 | insert: "the_field", | ||
259 | kind: Field, | ||
260 | detail: "u32", | ||
261 | }, | ||
262 | ] | ||
263 | "###); | ||
264 | } | ||
265 | |||
266 | #[test] | ||
267 | fn test_record_literal_enum_variant() { | ||
268 | let completions = complete( | ||
269 | r" | ||
270 | enum E { | ||
271 | A { a: u32 } | ||
272 | } | ||
273 | fn foo() { | ||
274 | let _ = E::A { <|> } | ||
275 | } | ||
276 | ", | ||
277 | ); | ||
278 | assert_debug_snapshot!(completions, @r###" | ||
279 | [ | ||
280 | CompletionItem { | ||
281 | label: "a", | ||
282 | source_range: [119; 119), | ||
283 | delete: [119; 119), | ||
284 | insert: "a", | ||
285 | kind: Field, | ||
286 | detail: "u32", | ||
287 | }, | ||
288 | ] | ||
289 | "###); | ||
290 | } | ||
291 | |||
292 | #[test] | ||
293 | fn test_record_literal_two_structs() { | ||
294 | let completions = complete( | ||
295 | r" | ||
296 | struct A { a: u32 } | ||
297 | struct B { b: u32 } | ||
298 | |||
299 | fn foo() { | ||
300 | let _: A = B { <|> } | ||
301 | } | ||
302 | ", | ||
303 | ); | ||
304 | assert_debug_snapshot!(completions, @r###" | ||
305 | [ | ||
306 | CompletionItem { | ||
307 | label: "b", | ||
308 | source_range: [119; 119), | ||
309 | delete: [119; 119), | ||
310 | insert: "b", | ||
311 | kind: Field, | ||
312 | detail: "u32", | ||
313 | }, | ||
314 | ] | ||
315 | "###); | ||
316 | } | ||
317 | |||
318 | #[test] | ||
319 | fn test_record_literal_generic_struct() { | ||
320 | let completions = complete( | ||
321 | r" | ||
322 | struct A<T> { a: T } | ||
323 | |||
324 | fn foo() { | ||
325 | let _: A<u32> = A { <|> } | ||
326 | } | ||
327 | ", | ||
328 | ); | ||
329 | assert_debug_snapshot!(completions, @r###" | ||
330 | [ | ||
331 | CompletionItem { | ||
332 | label: "a", | ||
333 | source_range: [93; 93), | ||
334 | delete: [93; 93), | ||
335 | insert: "a", | ||
336 | kind: Field, | ||
337 | detail: "u32", | ||
338 | }, | ||
339 | ] | ||
340 | "###); | ||
341 | } | ||
342 | |||
343 | #[test] | ||
344 | fn test_record_literal_field_in_simple_macro() { | ||
345 | let completions = complete( | ||
346 | r" | ||
347 | macro_rules! m { ($e:expr) => { $e } } | ||
348 | struct A { the_field: u32 } | ||
349 | fn foo() { | ||
350 | m!(A { the<|> }) | ||
351 | } | ||
352 | ", | ||
353 | ); | ||
354 | assert_debug_snapshot!(completions, @r###" | ||
355 | [ | ||
356 | CompletionItem { | ||
357 | label: "the_field", | ||
358 | source_range: [137; 140), | ||
359 | delete: [137; 140), | ||
360 | insert: "the_field", | ||
361 | kind: Field, | ||
362 | detail: "u32", | ||
363 | }, | ||
364 | ] | ||
365 | "###); | ||
366 | } | ||
367 | |||
368 | #[test] | ||
369 | fn only_missing_fields_are_completed() { | ||
370 | let completions = complete( | ||
371 | r" | ||
372 | struct S { | ||
373 | foo1: u32, | ||
374 | foo2: u32, | ||
375 | bar: u32, | ||
376 | baz: u32, | ||
377 | } | ||
378 | |||
379 | fn main() { | ||
380 | let foo1 = 1; | ||
381 | let s = S { | ||
382 | foo1, | ||
383 | foo2: 5, | ||
384 | <|> | ||
385 | } | ||
386 | } | ||
387 | ", | ||
388 | ); | ||
389 | assert_debug_snapshot!(completions, @r###" | ||
390 | [ | ||
391 | CompletionItem { | ||
392 | label: "bar", | ||
393 | source_range: [302; 302), | ||
394 | delete: [302; 302), | ||
395 | insert: "bar", | ||
396 | kind: Field, | ||
397 | detail: "u32", | ||
398 | }, | ||
399 | CompletionItem { | ||
400 | label: "baz", | ||
401 | source_range: [302; 302), | ||
402 | delete: [302; 302), | ||
403 | insert: "baz", | ||
404 | kind: Field, | ||
405 | detail: "u32", | ||
406 | }, | ||
407 | ] | ||
408 | "###); | ||
409 | } | ||
410 | } | ||
411 | } | ||
diff --git a/crates/ra_ide/src/completion/complete_record_literal.rs b/crates/ra_ide/src/completion/complete_record_literal.rs deleted file mode 100644 index e4e764f58..000000000 --- a/crates/ra_ide/src/completion/complete_record_literal.rs +++ /dev/null | |||
@@ -1,241 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::completion::{CompletionContext, Completions}; | ||
4 | use ra_syntax::SmolStr; | ||
5 | |||
6 | /// Complete fields in fields literals. | ||
7 | pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) { | ||
8 | let (ty, variant) = match ctx.record_lit_syntax.as_ref().and_then(|it| { | ||
9 | Some((ctx.sema.type_of_expr(&it.clone().into())?, ctx.sema.resolve_record_literal(it)?)) | ||
10 | }) { | ||
11 | Some(it) => it, | ||
12 | _ => return, | ||
13 | }; | ||
14 | |||
15 | let already_present_names: Vec<SmolStr> = ctx | ||
16 | .record_lit_syntax | ||
17 | .as_ref() | ||
18 | .and_then(|record_literal| record_literal.record_field_list()) | ||
19 | .map(|field_list| field_list.fields()) | ||
20 | .map(|fields| { | ||
21 | fields | ||
22 | .into_iter() | ||
23 | .filter_map(|field| field.name_ref()) | ||
24 | .map(|name_ref| name_ref.text().clone()) | ||
25 | .collect() | ||
26 | }) | ||
27 | .unwrap_or_default(); | ||
28 | |||
29 | for (field, field_ty) in ty.variant_fields(ctx.db, variant) { | ||
30 | if !already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string())) { | ||
31 | acc.add_field(ctx, field, &field_ty); | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #[cfg(test)] | ||
37 | mod tests { | ||
38 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
39 | use insta::assert_debug_snapshot; | ||
40 | |||
41 | fn complete(code: &str) -> Vec<CompletionItem> { | ||
42 | do_completion(code, CompletionKind::Reference) | ||
43 | } | ||
44 | |||
45 | #[test] | ||
46 | fn test_record_literal_deprecated_field() { | ||
47 | let completions = complete( | ||
48 | r" | ||
49 | struct A { | ||
50 | #[deprecated] | ||
51 | the_field: u32, | ||
52 | } | ||
53 | fn foo() { | ||
54 | A { the<|> } | ||
55 | } | ||
56 | ", | ||
57 | ); | ||
58 | assert_debug_snapshot!(completions, @r###" | ||
59 | [ | ||
60 | CompletionItem { | ||
61 | label: "the_field", | ||
62 | source_range: [142; 145), | ||
63 | delete: [142; 145), | ||
64 | insert: "the_field", | ||
65 | kind: Field, | ||
66 | detail: "u32", | ||
67 | deprecated: true, | ||
68 | }, | ||
69 | ] | ||
70 | "###); | ||
71 | } | ||
72 | |||
73 | #[test] | ||
74 | fn test_record_literal_field() { | ||
75 | let completions = complete( | ||
76 | r" | ||
77 | struct A { the_field: u32 } | ||
78 | fn foo() { | ||
79 | A { the<|> } | ||
80 | } | ||
81 | ", | ||
82 | ); | ||
83 | assert_debug_snapshot!(completions, @r###" | ||
84 | [ | ||
85 | CompletionItem { | ||
86 | label: "the_field", | ||
87 | source_range: [83; 86), | ||
88 | delete: [83; 86), | ||
89 | insert: "the_field", | ||
90 | kind: Field, | ||
91 | detail: "u32", | ||
92 | }, | ||
93 | ] | ||
94 | "###); | ||
95 | } | ||
96 | |||
97 | #[test] | ||
98 | fn test_record_literal_enum_variant() { | ||
99 | let completions = complete( | ||
100 | r" | ||
101 | enum E { | ||
102 | A { a: u32 } | ||
103 | } | ||
104 | fn foo() { | ||
105 | let _ = E::A { <|> } | ||
106 | } | ||
107 | ", | ||
108 | ); | ||
109 | assert_debug_snapshot!(completions, @r###" | ||
110 | [ | ||
111 | CompletionItem { | ||
112 | label: "a", | ||
113 | source_range: [119; 119), | ||
114 | delete: [119; 119), | ||
115 | insert: "a", | ||
116 | kind: Field, | ||
117 | detail: "u32", | ||
118 | }, | ||
119 | ] | ||
120 | "###); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn test_record_literal_two_structs() { | ||
125 | let completions = complete( | ||
126 | r" | ||
127 | struct A { a: u32 } | ||
128 | struct B { b: u32 } | ||
129 | |||
130 | fn foo() { | ||
131 | let _: A = B { <|> } | ||
132 | } | ||
133 | ", | ||
134 | ); | ||
135 | assert_debug_snapshot!(completions, @r###" | ||
136 | [ | ||
137 | CompletionItem { | ||
138 | label: "b", | ||
139 | source_range: [119; 119), | ||
140 | delete: [119; 119), | ||
141 | insert: "b", | ||
142 | kind: Field, | ||
143 | detail: "u32", | ||
144 | }, | ||
145 | ] | ||
146 | "###); | ||
147 | } | ||
148 | |||
149 | #[test] | ||
150 | fn test_record_literal_generic_struct() { | ||
151 | let completions = complete( | ||
152 | r" | ||
153 | struct A<T> { a: T } | ||
154 | |||
155 | fn foo() { | ||
156 | let _: A<u32> = A { <|> } | ||
157 | } | ||
158 | ", | ||
159 | ); | ||
160 | assert_debug_snapshot!(completions, @r###" | ||
161 | [ | ||
162 | CompletionItem { | ||
163 | label: "a", | ||
164 | source_range: [93; 93), | ||
165 | delete: [93; 93), | ||
166 | insert: "a", | ||
167 | kind: Field, | ||
168 | detail: "u32", | ||
169 | }, | ||
170 | ] | ||
171 | "###); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn test_record_literal_field_in_simple_macro() { | ||
176 | let completions = complete( | ||
177 | r" | ||
178 | macro_rules! m { ($e:expr) => { $e } } | ||
179 | struct A { the_field: u32 } | ||
180 | fn foo() { | ||
181 | m!(A { the<|> }) | ||
182 | } | ||
183 | ", | ||
184 | ); | ||
185 | assert_debug_snapshot!(completions, @r###" | ||
186 | [ | ||
187 | CompletionItem { | ||
188 | label: "the_field", | ||
189 | source_range: [137; 140), | ||
190 | delete: [137; 140), | ||
191 | insert: "the_field", | ||
192 | kind: Field, | ||
193 | detail: "u32", | ||
194 | }, | ||
195 | ] | ||
196 | "###); | ||
197 | } | ||
198 | |||
199 | #[test] | ||
200 | fn only_missing_fields_are_completed() { | ||
201 | let completions = complete( | ||
202 | r" | ||
203 | struct S { | ||
204 | foo1: u32, | ||
205 | foo2: u32, | ||
206 | bar: u32, | ||
207 | baz: u32, | ||
208 | } | ||
209 | |||
210 | fn main() { | ||
211 | let foo1 = 1; | ||
212 | let s = S { | ||
213 | foo1, | ||
214 | foo2: 5, | ||
215 | <|> | ||
216 | } | ||
217 | } | ||
218 | ", | ||
219 | ); | ||
220 | assert_debug_snapshot!(completions, @r###" | ||
221 | [ | ||
222 | CompletionItem { | ||
223 | label: "bar", | ||
224 | source_range: [302; 302), | ||
225 | delete: [302; 302), | ||
226 | insert: "bar", | ||
227 | kind: Field, | ||
228 | detail: "u32", | ||
229 | }, | ||
230 | CompletionItem { | ||
231 | label: "baz", | ||
232 | source_range: [302; 302), | ||
233 | delete: [302; 302), | ||
234 | insert: "baz", | ||
235 | kind: Field, | ||
236 | detail: "u32", | ||
237 | }, | ||
238 | ] | ||
239 | "###); | ||
240 | } | ||
241 | } | ||
diff --git a/crates/ra_ide/src/completion/complete_record_pattern.rs b/crates/ra_ide/src/completion/complete_record_pattern.rs deleted file mode 100644 index 962376428..000000000 --- a/crates/ra_ide/src/completion/complete_record_pattern.rs +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::completion::{CompletionContext, Completions}; | ||
4 | |||
5 | pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) { | ||
6 | let (ty, variant) = match ctx.record_lit_pat.as_ref().and_then(|it| { | ||
7 | Some((ctx.sema.type_of_pat(&it.clone().into())?, ctx.sema.resolve_record_pattern(it)?)) | ||
8 | }) { | ||
9 | Some(it) => it, | ||
10 | _ => return, | ||
11 | }; | ||
12 | |||
13 | for (field, field_ty) in ty.variant_fields(ctx.db, variant) { | ||
14 | acc.add_field(ctx, field, &field_ty); | ||
15 | } | ||
16 | } | ||
17 | |||
18 | #[cfg(test)] | ||
19 | mod tests { | ||
20 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
21 | use insta::assert_debug_snapshot; | ||
22 | |||
23 | fn complete(code: &str) -> Vec<CompletionItem> { | ||
24 | do_completion(code, CompletionKind::Reference) | ||
25 | } | ||
26 | |||
27 | #[test] | ||
28 | fn test_record_pattern_field() { | ||
29 | let completions = complete( | ||
30 | r" | ||
31 | struct S { foo: u32 } | ||
32 | |||
33 | fn process(f: S) { | ||
34 | match f { | ||
35 | S { f<|>: 92 } => (), | ||
36 | } | ||
37 | } | ||
38 | ", | ||
39 | ); | ||
40 | assert_debug_snapshot!(completions, @r###" | ||
41 | [ | ||
42 | CompletionItem { | ||
43 | label: "foo", | ||
44 | source_range: [117; 118), | ||
45 | delete: [117; 118), | ||
46 | insert: "foo", | ||
47 | kind: Field, | ||
48 | detail: "u32", | ||
49 | }, | ||
50 | ] | ||
51 | "###); | ||
52 | } | ||
53 | |||
54 | #[test] | ||
55 | fn test_record_pattern_enum_variant() { | ||
56 | let completions = complete( | ||
57 | r" | ||
58 | enum E { | ||
59 | S { foo: u32, bar: () } | ||
60 | } | ||
61 | |||
62 | fn process(e: E) { | ||
63 | match e { | ||
64 | E::S { <|> } => (), | ||
65 | } | ||
66 | } | ||
67 | ", | ||
68 | ); | ||
69 | assert_debug_snapshot!(completions, @r###" | ||
70 | [ | ||
71 | CompletionItem { | ||
72 | label: "bar", | ||
73 | source_range: [161; 161), | ||
74 | delete: [161; 161), | ||
75 | insert: "bar", | ||
76 | kind: Field, | ||
77 | detail: "()", | ||
78 | }, | ||
79 | CompletionItem { | ||
80 | label: "foo", | ||
81 | source_range: [161; 161), | ||
82 | delete: [161; 161), | ||
83 | insert: "foo", | ||
84 | kind: Field, | ||
85 | detail: "u32", | ||
86 | }, | ||
87 | ] | ||
88 | "###); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn test_record_pattern_field_in_simple_macro() { | ||
93 | let completions = complete( | ||
94 | r" | ||
95 | macro_rules! m { ($e:expr) => { $e } } | ||
96 | struct S { foo: u32 } | ||
97 | |||
98 | fn process(f: S) { | ||
99 | m!(match f { | ||
100 | S { f<|>: 92 } => (), | ||
101 | }) | ||
102 | } | ||
103 | ", | ||
104 | ); | ||
105 | assert_debug_snapshot!(completions, @r###" | ||
106 | [ | ||
107 | CompletionItem { | ||
108 | label: "foo", | ||
109 | source_range: [171; 172), | ||
110 | delete: [171; 172), | ||
111 | insert: "foo", | ||
112 | kind: Field, | ||
113 | detail: "u32", | ||
114 | }, | ||
115 | ] | ||
116 | "###); | ||
117 | } | ||
118 | } | ||
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 319e33b61..fdc0da2c5 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | }; | 11 | }; |
12 | use ra_text_edit::AtomTextEdit; | 12 | use ra_text_edit::AtomTextEdit; |
13 | 13 | ||
14 | use crate::{completion::CompletionOptions, FilePosition}; | 14 | use crate::{completion::CompletionConfig, FilePosition}; |
15 | 15 | ||
16 | /// `CompletionContext` is created early during completion to figure out, where | 16 | /// `CompletionContext` is created early during completion to figure out, where |
17 | /// exactly is the cursor, syntax-wise. | 17 | /// exactly is the cursor, syntax-wise. |
@@ -19,7 +19,7 @@ use crate::{completion::CompletionOptions, FilePosition}; | |||
19 | pub(crate) struct CompletionContext<'a> { | 19 | pub(crate) struct CompletionContext<'a> { |
20 | pub(super) sema: Semantics<'a, RootDatabase>, | 20 | pub(super) sema: Semantics<'a, RootDatabase>, |
21 | pub(super) db: &'a RootDatabase, | 21 | pub(super) db: &'a RootDatabase, |
22 | pub(super) options: &'a CompletionOptions, | 22 | pub(super) config: &'a CompletionConfig, |
23 | pub(super) offset: TextUnit, | 23 | pub(super) offset: TextUnit, |
24 | /// The token before the cursor, in the original file. | 24 | /// The token before the cursor, in the original file. |
25 | pub(super) original_token: SyntaxToken, | 25 | pub(super) original_token: SyntaxToken, |
@@ -61,7 +61,7 @@ impl<'a> CompletionContext<'a> { | |||
61 | pub(super) fn new( | 61 | pub(super) fn new( |
62 | db: &'a RootDatabase, | 62 | db: &'a RootDatabase, |
63 | position: FilePosition, | 63 | position: FilePosition, |
64 | options: &'a CompletionOptions, | 64 | config: &'a CompletionConfig, |
65 | ) -> Option<CompletionContext<'a>> { | 65 | ) -> Option<CompletionContext<'a>> { |
66 | let sema = Semantics::new(db); | 66 | let sema = Semantics::new(db); |
67 | 67 | ||
@@ -85,7 +85,7 @@ impl<'a> CompletionContext<'a> { | |||
85 | let mut ctx = CompletionContext { | 85 | let mut ctx = CompletionContext { |
86 | sema, | 86 | sema, |
87 | db, | 87 | db, |
88 | options, | 88 | config, |
89 | original_token, | 89 | original_token, |
90 | token, | 90 | token, |
91 | offset: position.offset, | 91 | offset: position.offset, |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 60f1b83f3..1c7c0924d 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -106,7 +106,7 @@ impl Completions { | |||
106 | }; | 106 | }; |
107 | 107 | ||
108 | // Add `<>` for generic types | 108 | // Add `<>` for generic types |
109 | if ctx.is_path_type && !ctx.has_type_args && ctx.options.add_call_parenthesis { | 109 | if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { |
110 | let has_non_default_type_params = match resolution { | 110 | let has_non_default_type_params = match resolution { |
111 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), | 111 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), |
112 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), | 112 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), |
@@ -211,14 +211,14 @@ impl Completions { | |||
211 | .detail(function_signature.to_string()); | 211 | .detail(function_signature.to_string()); |
212 | 212 | ||
213 | // If not an import, add parenthesis automatically. | 213 | // If not an import, add parenthesis automatically. |
214 | if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.options.add_call_parenthesis { | 214 | if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.config.add_call_parenthesis { |
215 | tested_by!(inserts_parens_for_function_calls); | 215 | tested_by!(inserts_parens_for_function_calls); |
216 | 216 | ||
217 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { | 217 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { |
218 | (format!("{}()$0", name), format!("{}()", name)) | 218 | (format!("{}()$0", name), format!("{}()", name)) |
219 | } else { | 219 | } else { |
220 | builder = builder.trigger_call_info(); | 220 | builder = builder.trigger_call_info(); |
221 | let snippet = if ctx.options.add_call_argument_snippets { | 221 | let snippet = if ctx.config.add_call_argument_snippets { |
222 | let to_skip = if has_self_param { 1 } else { 0 }; | 222 | let to_skip = if has_self_param { 1 } else { 0 }; |
223 | let function_params_snippet = function_signature | 223 | let function_params_snippet = function_signature |
224 | .parameter_names | 224 | .parameter_names |
@@ -311,7 +311,7 @@ mod tests { | |||
311 | 311 | ||
312 | use crate::completion::{ | 312 | use crate::completion::{ |
313 | test_utils::{do_completion, do_completion_with_options}, | 313 | test_utils::{do_completion, do_completion_with_options}, |
314 | CompletionItem, CompletionKind, CompletionOptions, | 314 | CompletionConfig, CompletionItem, CompletionKind, |
315 | }; | 315 | }; |
316 | 316 | ||
317 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { | 317 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { |
@@ -320,7 +320,7 @@ mod tests { | |||
320 | 320 | ||
321 | fn do_reference_completion_with_options( | 321 | fn do_reference_completion_with_options( |
322 | ra_fixture: &str, | 322 | ra_fixture: &str, |
323 | options: CompletionOptions, | 323 | options: CompletionConfig, |
324 | ) -> Vec<CompletionItem> { | 324 | ) -> Vec<CompletionItem> { |
325 | do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) | 325 | do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) |
326 | } | 326 | } |
@@ -589,7 +589,7 @@ mod tests { | |||
589 | s.f<|> | 589 | s.f<|> |
590 | } | 590 | } |
591 | ", | 591 | ", |
592 | CompletionOptions { | 592 | CompletionConfig { |
593 | add_call_argument_snippets: false, | 593 | add_call_argument_snippets: false, |
594 | .. Default::default() | 594 | .. Default::default() |
595 | } | 595 | } |
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs index 136857315..eb90b5279 100644 --- a/crates/ra_ide/src/completion/test_utils.rs +++ b/crates/ra_ide/src/completion/test_utils.rs | |||
@@ -1,19 +1,19 @@ | |||
1 | //! Runs completion for testing purposes. | 1 | //! Runs completion for testing purposes. |
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | completion::{completion_item::CompletionKind, CompletionOptions}, | 4 | completion::{completion_item::CompletionKind, CompletionConfig}, |
5 | mock_analysis::{analysis_and_position, single_file_with_position}, | 5 | mock_analysis::{analysis_and_position, single_file_with_position}, |
6 | CompletionItem, | 6 | CompletionItem, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | 9 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { |
10 | do_completion_with_options(code, kind, &CompletionOptions::default()) | 10 | do_completion_with_options(code, kind, &CompletionConfig::default()) |
11 | } | 11 | } |
12 | 12 | ||
13 | pub(crate) fn do_completion_with_options( | 13 | pub(crate) fn do_completion_with_options( |
14 | code: &str, | 14 | code: &str, |
15 | kind: CompletionKind, | 15 | kind: CompletionKind, |
16 | options: &CompletionOptions, | 16 | options: &CompletionConfig, |
17 | ) -> Vec<CompletionItem> { | 17 | ) -> Vec<CompletionItem> { |
18 | let (analysis, position) = if code.contains("//-") { | 18 | let (analysis, position) = if code.contains("//-") { |
19 | analysis_and_position(code) | 19 | analysis_and_position(code) |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index f4f0751c0..4b133b19b 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -11,14 +11,14 @@ use ra_syntax::{ | |||
11 | use crate::{FileId, FunctionSignature}; | 11 | use crate::{FileId, FunctionSignature}; |
12 | 12 | ||
13 | #[derive(Clone, Debug, PartialEq, Eq)] | 13 | #[derive(Clone, Debug, PartialEq, Eq)] |
14 | pub struct InlayHintsOptions { | 14 | pub struct InlayHintsConfig { |
15 | pub type_hints: bool, | 15 | pub type_hints: bool, |
16 | pub parameter_hints: bool, | 16 | pub parameter_hints: bool, |
17 | pub chaining_hints: bool, | 17 | pub chaining_hints: bool, |
18 | pub max_length: Option<usize>, | 18 | pub max_length: Option<usize>, |
19 | } | 19 | } |
20 | 20 | ||
21 | impl Default for InlayHintsOptions { | 21 | impl Default for InlayHintsConfig { |
22 | fn default() -> Self { | 22 | fn default() -> Self { |
23 | Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None } | 23 | Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None } |
24 | } | 24 | } |
@@ -41,7 +41,7 @@ pub struct InlayHint { | |||
41 | pub(crate) fn inlay_hints( | 41 | pub(crate) fn inlay_hints( |
42 | db: &RootDatabase, | 42 | db: &RootDatabase, |
43 | file_id: FileId, | 43 | file_id: FileId, |
44 | options: &InlayHintsOptions, | 44 | config: &InlayHintsConfig, |
45 | ) -> Vec<InlayHint> { | 45 | ) -> Vec<InlayHint> { |
46 | let _p = profile("inlay_hints"); | 46 | let _p = profile("inlay_hints"); |
47 | let sema = Semantics::new(db); | 47 | let sema = Semantics::new(db); |
@@ -50,14 +50,14 @@ pub(crate) fn inlay_hints( | |||
50 | let mut res = Vec::new(); | 50 | let mut res = Vec::new(); |
51 | for node in file.syntax().descendants() { | 51 | for node in file.syntax().descendants() { |
52 | if let Some(expr) = ast::Expr::cast(node.clone()) { | 52 | if let Some(expr) = ast::Expr::cast(node.clone()) { |
53 | get_chaining_hints(&mut res, &sema, options, expr); | 53 | get_chaining_hints(&mut res, &sema, config, expr); |
54 | } | 54 | } |
55 | 55 | ||
56 | match_ast! { | 56 | match_ast! { |
57 | match node { | 57 | match node { |
58 | ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, | 58 | ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); }, |
59 | ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, | 59 | ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); }, |
60 | ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, options, it); }, | 60 | ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); }, |
61 | _ => (), | 61 | _ => (), |
62 | } | 62 | } |
63 | } | 63 | } |
@@ -68,15 +68,14 @@ pub(crate) fn inlay_hints( | |||
68 | fn get_chaining_hints( | 68 | fn get_chaining_hints( |
69 | acc: &mut Vec<InlayHint>, | 69 | acc: &mut Vec<InlayHint>, |
70 | sema: &Semantics<RootDatabase>, | 70 | sema: &Semantics<RootDatabase>, |
71 | options: &InlayHintsOptions, | 71 | config: &InlayHintsConfig, |
72 | expr: ast::Expr, | 72 | expr: ast::Expr, |
73 | ) -> Option<()> { | 73 | ) -> Option<()> { |
74 | if !options.chaining_hints { | 74 | if !config.chaining_hints { |
75 | return None; | 75 | return None; |
76 | } | 76 | } |
77 | 77 | ||
78 | let ty = sema.type_of_expr(&expr)?; | 78 | if matches!(expr, ast::Expr::RecordLit(_)) { |
79 | if ty.is_unknown() { | ||
80 | return None; | 79 | return None; |
81 | } | 80 | } |
82 | 81 | ||
@@ -95,7 +94,18 @@ fn get_chaining_hints( | |||
95 | let next = tokens.next()?.kind(); | 94 | let next = tokens.next()?.kind(); |
96 | let next_next = tokens.next()?.kind(); | 95 | let next_next = tokens.next()?.kind(); |
97 | if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { | 96 | if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { |
98 | let label = ty.display_truncated(sema.db, options.max_length).to_string(); | 97 | let ty = sema.type_of_expr(&expr)?; |
98 | if ty.is_unknown() { | ||
99 | return None; | ||
100 | } | ||
101 | if matches!(expr, ast::Expr::PathExpr(_)) { | ||
102 | if let Some(Adt::Struct(st)) = ty.as_adt() { | ||
103 | if st.fields(sema.db).is_empty() { | ||
104 | return None; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | let label = ty.display_truncated(sema.db, config.max_length).to_string(); | ||
99 | acc.push(InlayHint { | 109 | acc.push(InlayHint { |
100 | range: expr.syntax().text_range(), | 110 | range: expr.syntax().text_range(), |
101 | kind: InlayKind::ChainingHint, | 111 | kind: InlayKind::ChainingHint, |
@@ -108,10 +118,10 @@ fn get_chaining_hints( | |||
108 | fn get_param_name_hints( | 118 | fn get_param_name_hints( |
109 | acc: &mut Vec<InlayHint>, | 119 | acc: &mut Vec<InlayHint>, |
110 | sema: &Semantics<RootDatabase>, | 120 | sema: &Semantics<RootDatabase>, |
111 | options: &InlayHintsOptions, | 121 | config: &InlayHintsConfig, |
112 | expr: ast::Expr, | 122 | expr: ast::Expr, |
113 | ) -> Option<()> { | 123 | ) -> Option<()> { |
114 | if !options.parameter_hints { | 124 | if !config.parameter_hints { |
115 | return None; | 125 | return None; |
116 | } | 126 | } |
117 | 127 | ||
@@ -148,10 +158,10 @@ fn get_param_name_hints( | |||
148 | fn get_bind_pat_hints( | 158 | fn get_bind_pat_hints( |
149 | acc: &mut Vec<InlayHint>, | 159 | acc: &mut Vec<InlayHint>, |
150 | sema: &Semantics<RootDatabase>, | 160 | sema: &Semantics<RootDatabase>, |
151 | options: &InlayHintsOptions, | 161 | config: &InlayHintsConfig, |
152 | pat: ast::BindPat, | 162 | pat: ast::BindPat, |
153 | ) -> Option<()> { | 163 | ) -> Option<()> { |
154 | if !options.type_hints { | 164 | if !config.type_hints { |
155 | return None; | 165 | return None; |
156 | } | 166 | } |
157 | 167 | ||
@@ -164,7 +174,7 @@ fn get_bind_pat_hints( | |||
164 | acc.push(InlayHint { | 174 | acc.push(InlayHint { |
165 | range: pat.syntax().text_range(), | 175 | range: pat.syntax().text_range(), |
166 | kind: InlayKind::TypeHint, | 176 | kind: InlayKind::TypeHint, |
167 | label: ty.display_truncated(sema.db, options.max_length).to_string().into(), | 177 | label: ty.display_truncated(sema.db, config.max_length).to_string().into(), |
168 | }); | 178 | }); |
169 | Some(()) | 179 | Some(()) |
170 | } | 180 | } |
@@ -270,7 +280,7 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option< | |||
270 | 280 | ||
271 | #[cfg(test)] | 281 | #[cfg(test)] |
272 | mod tests { | 282 | mod tests { |
273 | use crate::inlay_hints::InlayHintsOptions; | 283 | use crate::inlay_hints::InlayHintsConfig; |
274 | use insta::assert_debug_snapshot; | 284 | use insta::assert_debug_snapshot; |
275 | 285 | ||
276 | use crate::mock_analysis::single_file; | 286 | use crate::mock_analysis::single_file; |
@@ -284,7 +294,7 @@ mod tests { | |||
284 | let _x = foo(4, 4); | 294 | let _x = foo(4, 4); |
285 | }"#, | 295 | }"#, |
286 | ); | 296 | ); |
287 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" | 297 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" |
288 | [ | 298 | [ |
289 | InlayHint { | 299 | InlayHint { |
290 | range: [106; 107), | 300 | range: [106; 107), |
@@ -308,7 +318,7 @@ mod tests { | |||
308 | let _x = foo(4, 4); | 318 | let _x = foo(4, 4); |
309 | }"#, | 319 | }"#, |
310 | ); | 320 | ); |
311 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###); | 321 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###); |
312 | } | 322 | } |
313 | 323 | ||
314 | #[test] | 324 | #[test] |
@@ -320,7 +330,7 @@ mod tests { | |||
320 | let _x = foo(4, 4); | 330 | let _x = foo(4, 4); |
321 | }"#, | 331 | }"#, |
322 | ); | 332 | ); |
323 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" | 333 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" |
324 | [ | 334 | [ |
325 | InlayHint { | 335 | InlayHint { |
326 | range: [97; 99), | 336 | range: [97; 99), |
@@ -344,7 +354,7 @@ fn main() { | |||
344 | }"#, | 354 | }"#, |
345 | ); | 355 | ); |
346 | 356 | ||
347 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 357 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
348 | [ | 358 | [ |
349 | InlayHint { | 359 | InlayHint { |
350 | range: [69; 71), | 360 | range: [69; 71), |
@@ -401,7 +411,7 @@ fn main() { | |||
401 | }"#, | 411 | }"#, |
402 | ); | 412 | ); |
403 | 413 | ||
404 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 414 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
405 | [ | 415 | [ |
406 | InlayHint { | 416 | InlayHint { |
407 | range: [193; 197), | 417 | range: [193; 197), |
@@ -481,7 +491,7 @@ fn main() { | |||
481 | }"#, | 491 | }"#, |
482 | ); | 492 | ); |
483 | 493 | ||
484 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 494 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
485 | [ | 495 | [ |
486 | InlayHint { | 496 | InlayHint { |
487 | range: [21; 30), | 497 | range: [21; 30), |
@@ -545,7 +555,7 @@ fn main() { | |||
545 | }"#, | 555 | }"#, |
546 | ); | 556 | ); |
547 | 557 | ||
548 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 558 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
549 | [ | 559 | [ |
550 | InlayHint { | 560 | InlayHint { |
551 | range: [21; 30), | 561 | range: [21; 30), |
@@ -595,7 +605,7 @@ fn main() { | |||
595 | }"#, | 605 | }"#, |
596 | ); | 606 | ); |
597 | 607 | ||
598 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 608 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
599 | [ | 609 | [ |
600 | InlayHint { | 610 | InlayHint { |
601 | range: [188; 192), | 611 | range: [188; 192), |
@@ -690,7 +700,7 @@ fn main() { | |||
690 | }"#, | 700 | }"#, |
691 | ); | 701 | ); |
692 | 702 | ||
693 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 703 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
694 | [ | 704 | [ |
695 | InlayHint { | 705 | InlayHint { |
696 | range: [188; 192), | 706 | range: [188; 192), |
@@ -785,7 +795,7 @@ fn main() { | |||
785 | }"#, | 795 | }"#, |
786 | ); | 796 | ); |
787 | 797 | ||
788 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 798 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
789 | [ | 799 | [ |
790 | InlayHint { | 800 | InlayHint { |
791 | range: [252; 256), | 801 | range: [252; 256), |
@@ -857,7 +867,7 @@ fn main() { | |||
857 | }"#, | 867 | }"#, |
858 | ); | 868 | ); |
859 | 869 | ||
860 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions { max_length: Some(8), ..Default::default() }).unwrap(), @r###" | 870 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###" |
861 | [ | 871 | [ |
862 | InlayHint { | 872 | InlayHint { |
863 | range: [74; 75), | 873 | range: [74; 75), |
@@ -945,7 +955,7 @@ fn main() { | |||
945 | }"#, | 955 | }"#, |
946 | ); | 956 | ); |
947 | 957 | ||
948 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" | 958 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###" |
949 | [ | 959 | [ |
950 | InlayHint { | 960 | InlayHint { |
951 | range: [798; 809), | 961 | range: [798; 809), |
@@ -1067,7 +1077,7 @@ fn main() { | |||
1067 | }"#, | 1077 | }"#, |
1068 | ); | 1078 | ); |
1069 | 1079 | ||
1070 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions { max_length: Some(8), ..Default::default() }).unwrap(), @r###" | 1080 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###" |
1071 | [] | 1081 | [] |
1072 | "### | 1082 | "### |
1073 | ); | 1083 | ); |
@@ -1093,7 +1103,7 @@ fn main() { | |||
1093 | }"#, | 1103 | }"#, |
1094 | ); | 1104 | ); |
1095 | 1105 | ||
1096 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions { max_length: Some(8), ..Default::default() }).unwrap(), @r###" | 1106 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###" |
1097 | [] | 1107 | [] |
1098 | "### | 1108 | "### |
1099 | ); | 1109 | ); |
@@ -1115,7 +1125,7 @@ fn main() { | |||
1115 | .into_c(); | 1125 | .into_c(); |
1116 | }"#, | 1126 | }"#, |
1117 | ); | 1127 | ); |
1118 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | 1128 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" |
1119 | [ | 1129 | [ |
1120 | InlayHint { | 1130 | InlayHint { |
1121 | range: [232; 269), | 1131 | range: [232; 269), |
@@ -1144,7 +1154,7 @@ fn main() { | |||
1144 | let c = A(B(C)).into_b().into_c(); | 1154 | let c = A(B(C)).into_b().into_c(); |
1145 | }"#, | 1155 | }"#, |
1146 | ); | 1156 | ); |
1147 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###); | 1157 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###); |
1148 | } | 1158 | } |
1149 | 1159 | ||
1150 | #[test] | 1160 | #[test] |
@@ -1154,32 +1164,35 @@ fn main() { | |||
1154 | struct A { pub b: B } | 1164 | struct A { pub b: B } |
1155 | struct B { pub c: C } | 1165 | struct B { pub c: C } |
1156 | struct C(pub bool); | 1166 | struct C(pub bool); |
1167 | struct D; | ||
1168 | |||
1169 | impl D { | ||
1170 | fn foo(&self) -> i32 { 42 } | ||
1171 | } | ||
1157 | 1172 | ||
1158 | fn main() { | 1173 | fn main() { |
1159 | let x = A { b: B { c: C(true) } } | 1174 | let x = A { b: B { c: C(true) } } |
1160 | .b | 1175 | .b |
1161 | .c | 1176 | .c |
1162 | .0; | 1177 | .0; |
1178 | let x = D | ||
1179 | .foo(); | ||
1163 | }"#, | 1180 | }"#, |
1164 | ); | 1181 | ); |
1165 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | 1182 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" |
1166 | [ | 1183 | [ |
1167 | InlayHint { | 1184 | InlayHint { |
1168 | range: [150; 221), | 1185 | range: [252; 323), |
1169 | kind: ChainingHint, | 1186 | kind: ChainingHint, |
1170 | label: "C", | 1187 | label: "C", |
1171 | }, | 1188 | }, |
1172 | InlayHint { | 1189 | InlayHint { |
1173 | range: [150; 198), | 1190 | range: [252; 300), |
1174 | kind: ChainingHint, | 1191 | kind: ChainingHint, |
1175 | label: "B", | 1192 | label: "B", |
1176 | }, | 1193 | }, |
1177 | InlayHint { | 1194 | ] |
1178 | range: [150; 175), | 1195 | "###); |
1179 | kind: ChainingHint, | ||
1180 | label: "A", | ||
1181 | }, | ||
1182 | ]"###); | ||
1183 | } | 1196 | } |
1184 | 1197 | ||
1185 | #[test] | 1198 | #[test] |
@@ -1204,7 +1217,7 @@ fn main() { | |||
1204 | .into_c(); | 1217 | .into_c(); |
1205 | }"#, | 1218 | }"#, |
1206 | ); | 1219 | ); |
1207 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | 1220 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" |
1208 | [ | 1221 | [ |
1209 | InlayHint { | 1222 | InlayHint { |
1210 | range: [403; 452), | 1223 | range: [403; 452), |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index e43414985..285381086 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -62,13 +62,13 @@ use crate::display::ToNav; | |||
62 | pub use crate::{ | 62 | pub use crate::{ |
63 | assists::{Assist, AssistId}, | 63 | assists::{Assist, AssistId}, |
64 | call_hierarchy::CallItem, | 64 | call_hierarchy::CallItem, |
65 | completion::{CompletionItem, CompletionItemKind, CompletionOptions, InsertTextFormat}, | 65 | completion::{CompletionConfig, CompletionItem, CompletionItemKind, InsertTextFormat}, |
66 | diagnostics::Severity, | 66 | diagnostics::Severity, |
67 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, | 67 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, |
68 | expand_macro::ExpandedMacro, | 68 | expand_macro::ExpandedMacro, |
69 | folding_ranges::{Fold, FoldKind}, | 69 | folding_ranges::{Fold, FoldKind}, |
70 | hover::HoverResult, | 70 | hover::HoverResult, |
71 | inlay_hints::{InlayHint, InlayHintsOptions, InlayKind}, | 71 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
72 | references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, | 72 | references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, |
73 | runnables::{Runnable, RunnableKind, TestId}, | 73 | runnables::{Runnable, RunnableKind, TestId}, |
74 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 74 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
@@ -138,6 +138,11 @@ impl AnalysisHost { | |||
138 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { | 138 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { |
139 | AnalysisHost { db: RootDatabase::new(lru_capacity) } | 139 | AnalysisHost { db: RootDatabase::new(lru_capacity) } |
140 | } | 140 | } |
141 | |||
142 | pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) { | ||
143 | self.db.update_lru_capacity(lru_capacity); | ||
144 | } | ||
145 | |||
141 | /// Returns a snapshot of the current state, which you can query for | 146 | /// Returns a snapshot of the current state, which you can query for |
142 | /// semantic information. | 147 | /// semantic information. |
143 | pub fn analysis(&self) -> Analysis { | 148 | pub fn analysis(&self) -> Analysis { |
@@ -320,9 +325,9 @@ impl Analysis { | |||
320 | pub fn inlay_hints( | 325 | pub fn inlay_hints( |
321 | &self, | 326 | &self, |
322 | file_id: FileId, | 327 | file_id: FileId, |
323 | inlay_hint_opts: &InlayHintsOptions, | 328 | config: &InlayHintsConfig, |
324 | ) -> Cancelable<Vec<InlayHint>> { | 329 | ) -> Cancelable<Vec<InlayHint>> { |
325 | self.with_db(|db| inlay_hints::inlay_hints(db, file_id, inlay_hint_opts)) | 330 | self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config)) |
326 | } | 331 | } |
327 | 332 | ||
328 | /// Returns the set of folding ranges. | 333 | /// Returns the set of folding ranges. |
@@ -445,9 +450,9 @@ impl Analysis { | |||
445 | pub fn completions( | 450 | pub fn completions( |
446 | &self, | 451 | &self, |
447 | position: FilePosition, | 452 | position: FilePosition, |
448 | options: &CompletionOptions, | 453 | config: &CompletionConfig, |
449 | ) -> Cancelable<Option<Vec<CompletionItem>>> { | 454 | ) -> Cancelable<Option<Vec<CompletionItem>>> { |
450 | self.with_db(|db| completion::completions(db, position, options).map(Into::into)) | 455 | self.with_db(|db| completion::completions(db, position, config).map(Into::into)) |
451 | } | 456 | } |
452 | 457 | ||
453 | /// Computes assists (aka code actions aka intentions) for the given | 458 | /// Computes assists (aka code actions aka intentions) for the given |
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index 1c9710a5d..1abb891c1 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs | |||
@@ -5,7 +5,7 @@ use ra_db::{SourceDatabase, SourceDatabaseExt}; | |||
5 | use ra_ide_db::symbol_index::SymbolsDatabase; | 5 | use ra_ide_db::symbol_index::SymbolsDatabase; |
6 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
7 | use ra_syntax::ast::make::try_expr_from_text; | 7 | use ra_syntax::ast::make::try_expr_from_text; |
8 | use ra_syntax::ast::{AstToken, Comment}; | 8 | use ra_syntax::ast::{AstToken, Comment, RecordField, RecordLit}; |
9 | use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; | 9 | use ra_syntax::{AstNode, SyntaxElement, SyntaxNode}; |
10 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 10 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
11 | use rustc_hash::FxHashMap; | 11 | use rustc_hash::FxHashMap; |
@@ -186,47 +186,102 @@ fn create_name<'a>(name: &str, vars: &'a mut Vec<Var>) -> Result<&'a str, SsrErr | |||
186 | } | 186 | } |
187 | 187 | ||
188 | fn find(pattern: &SsrPattern, code: &SyntaxNode) -> SsrMatches { | 188 | fn find(pattern: &SsrPattern, code: &SyntaxNode) -> SsrMatches { |
189 | fn check_record_lit( | ||
190 | pattern: RecordLit, | ||
191 | code: RecordLit, | ||
192 | placeholders: &[Var], | ||
193 | match_: Match, | ||
194 | ) -> Option<Match> { | ||
195 | let match_ = check_opt_nodes(pattern.path(), code.path(), placeholders, match_)?; | ||
196 | |||
197 | let mut pattern_fields = | ||
198 | pattern.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]); | ||
199 | let mut code_fields = | ||
200 | code.record_field_list().map(|x| x.fields().collect()).unwrap_or(vec![]); | ||
201 | |||
202 | if pattern_fields.len() != code_fields.len() { | ||
203 | return None; | ||
204 | } | ||
205 | |||
206 | let by_name = |a: &RecordField, b: &RecordField| { | ||
207 | a.name_ref() | ||
208 | .map(|x| x.syntax().text().to_string()) | ||
209 | .cmp(&b.name_ref().map(|x| x.syntax().text().to_string())) | ||
210 | }; | ||
211 | pattern_fields.sort_by(by_name); | ||
212 | code_fields.sort_by(by_name); | ||
213 | |||
214 | pattern_fields.into_iter().zip(code_fields.into_iter()).fold( | ||
215 | Some(match_), | ||
216 | |accum, (a, b)| { | ||
217 | accum.and_then(|match_| check_opt_nodes(Some(a), Some(b), placeholders, match_)) | ||
218 | }, | ||
219 | ) | ||
220 | } | ||
221 | |||
222 | fn check_opt_nodes( | ||
223 | pattern: Option<impl AstNode>, | ||
224 | code: Option<impl AstNode>, | ||
225 | placeholders: &[Var], | ||
226 | match_: Match, | ||
227 | ) -> Option<Match> { | ||
228 | match (pattern, code) { | ||
229 | (Some(pattern), Some(code)) => check( | ||
230 | &SyntaxElement::from(pattern.syntax().clone()), | ||
231 | &SyntaxElement::from(code.syntax().clone()), | ||
232 | placeholders, | ||
233 | match_, | ||
234 | ), | ||
235 | (None, None) => Some(match_), | ||
236 | _ => None, | ||
237 | } | ||
238 | } | ||
239 | |||
189 | fn check( | 240 | fn check( |
190 | pattern: &SyntaxElement, | 241 | pattern: &SyntaxElement, |
191 | code: &SyntaxElement, | 242 | code: &SyntaxElement, |
192 | placeholders: &[Var], | 243 | placeholders: &[Var], |
193 | mut match_: Match, | 244 | mut match_: Match, |
194 | ) -> Option<Match> { | 245 | ) -> Option<Match> { |
195 | match (pattern, code) { | 246 | match (&pattern, &code) { |
196 | (SyntaxElement::Token(ref pattern), SyntaxElement::Token(ref code)) => { | 247 | (SyntaxElement::Token(pattern), SyntaxElement::Token(code)) => { |
197 | if pattern.text() == code.text() { | 248 | if pattern.text() == code.text() { |
198 | Some(match_) | 249 | Some(match_) |
199 | } else { | 250 | } else { |
200 | None | 251 | None |
201 | } | 252 | } |
202 | } | 253 | } |
203 | (SyntaxElement::Node(ref pattern), SyntaxElement::Node(ref code)) => { | 254 | (SyntaxElement::Node(pattern), SyntaxElement::Node(code)) => { |
204 | if placeholders.iter().any(|n| n.0.as_str() == pattern.text()) { | 255 | if placeholders.iter().any(|n| n.0.as_str() == pattern.text()) { |
205 | match_.binding.insert(Var(pattern.text().to_string()), code.clone()); | 256 | match_.binding.insert(Var(pattern.text().to_string()), code.clone()); |
206 | Some(match_) | 257 | Some(match_) |
207 | } else { | 258 | } else { |
208 | let mut pattern_children = pattern | 259 | if let (Some(pattern), Some(code)) = |
209 | .children_with_tokens() | 260 | (RecordLit::cast(pattern.clone()), RecordLit::cast(code.clone())) |
210 | .filter(|element| !element.kind().is_trivia()); | 261 | { |
211 | let mut code_children = | 262 | check_record_lit(pattern, code, placeholders, match_) |
212 | code.children_with_tokens().filter(|element| !element.kind().is_trivia()); | 263 | } else { |
213 | let new_ignored_comments = code.children_with_tokens().filter_map(|element| { | 264 | let mut pattern_children = pattern |
214 | element.as_token().and_then(|token| Comment::cast(token.clone())) | 265 | .children_with_tokens() |
215 | }); | 266 | .filter(|element| !element.kind().is_trivia()); |
216 | match_.ignored_comments.extend(new_ignored_comments); | 267 | let mut code_children = code |
217 | let match_from_children = pattern_children | 268 | .children_with_tokens() |
218 | .by_ref() | 269 | .filter(|element| !element.kind().is_trivia()); |
219 | .zip(code_children.by_ref()) | 270 | let new_ignored_comments = |
220 | .fold(Some(match_), |accum, (a, b)| { | 271 | code.children_with_tokens().filter_map(|element| { |
221 | accum.and_then(|match_| check(&a, &b, placeholders, match_)) | 272 | element.as_token().and_then(|token| Comment::cast(token.clone())) |
222 | }); | 273 | }); |
223 | match_from_children.and_then(|match_| { | 274 | match_.ignored_comments.extend(new_ignored_comments); |
224 | if pattern_children.count() == 0 && code_children.count() == 0 { | 275 | pattern_children |
225 | Some(match_) | 276 | .by_ref() |
226 | } else { | 277 | .zip(code_children.by_ref()) |
227 | None | 278 | .fold(Some(match_), |accum, (a, b)| { |
228 | } | 279 | accum.and_then(|match_| check(&a, &b, placeholders, match_)) |
229 | }) | 280 | }) |
281 | .filter(|_| { | ||
282 | pattern_children.next().is_none() && code_children.next().is_none() | ||
283 | }) | ||
284 | } | ||
230 | } | 285 | } |
231 | } | 286 | } |
232 | _ => None, | 287 | _ => None, |
@@ -434,4 +489,13 @@ mod tests { | |||
434 | "fn main() { bar(5)/* using 5 */ }", | 489 | "fn main() { bar(5)/* using 5 */ }", |
435 | ) | 490 | ) |
436 | } | 491 | } |
492 | |||
493 | #[test] | ||
494 | fn ssr_struct_lit() { | ||
495 | assert_ssr_transform( | ||
496 | "foo{a: $a:expr, b: $b:expr} ==>> foo::new($a, $b)", | ||
497 | "fn main() { foo{b:2, a:1} }", | ||
498 | "fn main() { foo::new(1, 2) }", | ||
499 | ) | ||
500 | } | ||
437 | } | 501 | } |