diff options
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 988 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_keyword.rs | 35 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_qualified_path.rs | 39 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 911 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/test_utils.rs | 21 |
6 files changed, 695 insertions, 1301 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index ee4e24fca..667a8b949 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -1,17 +1,12 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Completes references after dot (fields and method calls). |
2 | 2 | ||
3 | use hir::{HasVisibility, Type}; | 3 | use hir::{HasVisibility, Type}; |
4 | |||
5 | use crate::{ | ||
6 | completion::{ | ||
7 | completion_context::CompletionContext, | ||
8 | completion_item::{CompletionKind, Completions}, | ||
9 | }, | ||
10 | CompletionItem, | ||
11 | }; | ||
12 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use test_utils::mark; | ||
13 | 6 | ||
14 | /// Complete dot accesses, i.e. fields or methods (and .await syntax). | 7 | use crate::completion::{completion_context::CompletionContext, completion_item::Completions}; |
8 | |||
9 | /// Complete dot accesses, i.e. fields or methods. | ||
15 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
16 | let dot_receiver = match &ctx.dot_receiver { | 11 | let dot_receiver = match &ctx.dot_receiver { |
17 | Some(expr) => expr, | 12 | Some(expr) => expr, |
@@ -23,18 +18,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
23 | _ => return, | 18 | _ => return, |
24 | }; | 19 | }; |
25 | 20 | ||
26 | if !ctx.is_call { | 21 | if ctx.is_call { |
22 | mark::hit!(test_no_struct_field_completion_for_method_call); | ||
23 | } else { | ||
27 | complete_fields(acc, ctx, &receiver_ty); | 24 | complete_fields(acc, ctx, &receiver_ty); |
28 | } | 25 | } |
29 | complete_methods(acc, ctx, &receiver_ty); | 26 | complete_methods(acc, ctx, &receiver_ty); |
30 | |||
31 | // Suggest .await syntax for types that implement Future trait | ||
32 | if receiver_ty.impls_future(ctx.db) { | ||
33 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") | ||
34 | .detail("expr.await") | ||
35 | .insert_text("await") | ||
36 | .add_to(acc); | ||
37 | } | ||
38 | } | 27 | } |
39 | 28 | ||
40 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | 29 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { |
@@ -72,801 +61,356 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T | |||
72 | 61 | ||
73 | #[cfg(test)] | 62 | #[cfg(test)] |
74 | mod tests { | 63 | mod tests { |
75 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 64 | use expect::{expect, Expect}; |
76 | use insta::assert_debug_snapshot; | 65 | use test_utils::mark; |
66 | |||
67 | use crate::completion::{test_utils::completion_list, CompletionKind}; | ||
77 | 68 | ||
78 | fn do_ref_completion(code: &str) -> Vec<CompletionItem> { | 69 | fn check(ra_fixture: &str, expect: Expect) { |
79 | do_completion(code, CompletionKind::Reference) | 70 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
71 | expect.assert_eq(&actual); | ||
80 | } | 72 | } |
81 | 73 | ||
82 | #[test] | 74 | #[test] |
83 | fn test_struct_field_completion() { | 75 | fn test_struct_field_and_method_completion() { |
84 | assert_debug_snapshot!( | 76 | check( |
85 | do_ref_completion( | 77 | r#" |
86 | r" | 78 | struct S { foo: u32 } |
87 | struct A { the_field: u32 } | 79 | impl S { |
88 | fn foo(a: A) { | 80 | fn bar(&self) {} |
89 | a.<|> | 81 | } |
90 | } | 82 | fn foo(s: S) { s.<|> } |
91 | ", | 83 | "#, |
92 | ), | 84 | expect![[r#" |
93 | @r###" | 85 | me bar() fn bar(&self) |
94 | [ | 86 | fd foo u32 |
95 | CompletionItem { | 87 | "#]], |
96 | label: "the_field", | ||
97 | source_range: 45..45, | ||
98 | delete: 45..45, | ||
99 | insert: "the_field", | ||
100 | kind: Field, | ||
101 | detail: "u32", | ||
102 | }, | ||
103 | ] | ||
104 | "### | ||
105 | ); | 88 | ); |
106 | } | 89 | } |
107 | 90 | ||
108 | #[test] | 91 | #[test] |
109 | fn test_struct_field_completion_self() { | 92 | fn test_struct_field_completion_self() { |
110 | assert_debug_snapshot!( | 93 | check( |
111 | do_ref_completion( | 94 | r#" |
112 | r" | 95 | struct S { the_field: (u32,) } |
113 | struct A { | 96 | impl S { |
114 | /// This is the_field | 97 | fn foo(self) { self.<|> } |
115 | the_field: (u32,) | 98 | } |
116 | } | 99 | "#, |
117 | impl A { | 100 | expect![[r#" |
118 | fn foo(self) { | 101 | me foo() fn foo(self) |
119 | self.<|> | 102 | fd the_field (u32,) |
120 | } | 103 | "#]], |
121 | } | 104 | ) |
122 | ", | ||
123 | ), | ||
124 | @r###" | ||
125 | [ | ||
126 | CompletionItem { | ||
127 | label: "foo()", | ||
128 | source_range: 102..102, | ||
129 | delete: 102..102, | ||
130 | insert: "foo()$0", | ||
131 | kind: Method, | ||
132 | lookup: "foo", | ||
133 | detail: "fn foo(self)", | ||
134 | }, | ||
135 | CompletionItem { | ||
136 | label: "the_field", | ||
137 | source_range: 102..102, | ||
138 | delete: 102..102, | ||
139 | insert: "the_field", | ||
140 | kind: Field, | ||
141 | detail: "(u32,)", | ||
142 | documentation: Documentation( | ||
143 | "This is the_field", | ||
144 | ), | ||
145 | }, | ||
146 | ] | ||
147 | "### | ||
148 | ); | ||
149 | } | 105 | } |
150 | 106 | ||
151 | #[test] | 107 | #[test] |
152 | fn test_struct_field_completion_autoderef() { | 108 | fn test_struct_field_completion_autoderef() { |
153 | assert_debug_snapshot!( | 109 | check( |
154 | do_ref_completion( | 110 | r#" |
155 | r" | 111 | struct A { the_field: (u32, i32) } |
156 | struct A { the_field: (u32, i32) } | 112 | impl A { |
157 | impl A { | 113 | fn foo(&self) { self.<|> } |
158 | fn foo(&self) { | 114 | } |
159 | self.<|> | 115 | "#, |
160 | } | 116 | expect![[r#" |
161 | } | 117 | me foo() fn foo(&self) |
162 | ", | 118 | fd the_field (u32, i32) |
163 | ), | 119 | "#]], |
164 | @r###" | 120 | ) |
165 | [ | ||
166 | CompletionItem { | ||
167 | label: "foo()", | ||
168 | source_range: 77..77, | ||
169 | delete: 77..77, | ||
170 | insert: "foo()$0", | ||
171 | kind: Method, | ||
172 | lookup: "foo", | ||
173 | detail: "fn foo(&self)", | ||
174 | }, | ||
175 | CompletionItem { | ||
176 | label: "the_field", | ||
177 | source_range: 77..77, | ||
178 | delete: 77..77, | ||
179 | insert: "the_field", | ||
180 | kind: Field, | ||
181 | detail: "(u32, i32)", | ||
182 | }, | ||
183 | ] | ||
184 | "### | ||
185 | ); | ||
186 | } | 121 | } |
187 | 122 | ||
188 | #[test] | 123 | #[test] |
189 | fn test_no_struct_field_completion_for_method_call() { | 124 | fn test_no_struct_field_completion_for_method_call() { |
190 | assert_debug_snapshot!( | 125 | mark::check!(test_no_struct_field_completion_for_method_call); |
191 | do_ref_completion( | 126 | check( |
192 | r" | 127 | r#" |
193 | struct A { the_field: u32 } | 128 | struct A { the_field: u32 } |
194 | fn foo(a: A) { | 129 | fn foo(a: A) { a.<|>() } |
195 | a.<|>() | 130 | "#, |
196 | } | 131 | expect![[""]], |
197 | ", | ||
198 | ), | ||
199 | @"[]" | ||
200 | ); | 132 | ); |
201 | } | 133 | } |
202 | 134 | ||
203 | #[test] | 135 | #[test] |
204 | fn test_struct_field_visibility_private() { | 136 | fn test_visibility_filtering() { |
205 | assert_debug_snapshot!( | 137 | check( |
206 | do_ref_completion( | 138 | r#" |
207 | r" | 139 | mod inner { |
208 | mod inner { | 140 | pub struct A { |
209 | struct A { | 141 | private_field: u32, |
210 | private_field: u32, | 142 | pub pub_field: u32, |
211 | pub pub_field: u32, | 143 | pub(crate) crate_field: u32, |
212 | pub(crate) crate_field: u32, | 144 | pub(super) super_field: u32, |
213 | pub(super) super_field: u32, | ||
214 | } | ||
215 | } | ||
216 | fn foo(a: inner::A) { | ||
217 | a.<|> | ||
218 | } | ||
219 | ", | ||
220 | ), | ||
221 | @r###" | ||
222 | [ | ||
223 | CompletionItem { | ||
224 | label: "crate_field", | ||
225 | source_range: 192..192, | ||
226 | delete: 192..192, | ||
227 | insert: "crate_field", | ||
228 | kind: Field, | ||
229 | detail: "u32", | ||
230 | }, | ||
231 | CompletionItem { | ||
232 | label: "pub_field", | ||
233 | source_range: 192..192, | ||
234 | delete: 192..192, | ||
235 | insert: "pub_field", | ||
236 | kind: Field, | ||
237 | detail: "u32", | ||
238 | }, | ||
239 | CompletionItem { | ||
240 | label: "super_field", | ||
241 | source_range: 192..192, | ||
242 | delete: 192..192, | ||
243 | insert: "super_field", | ||
244 | kind: Field, | ||
245 | detail: "u32", | ||
246 | }, | ||
247 | ] | ||
248 | "### | ||
249 | ); | ||
250 | } | 145 | } |
251 | 146 | } | |
252 | #[test] | 147 | fn foo(a: inner::A) { a.<|> } |
253 | fn test_union_field_completion() { | 148 | "#, |
254 | assert_debug_snapshot!( | 149 | expect![[r#" |
255 | do_ref_completion( | 150 | fd crate_field u32 |
256 | r" | 151 | fd pub_field u32 |
257 | union Un { | 152 | fd super_field u32 |
258 | field: u8, | 153 | "#]], |
259 | other: u16, | ||
260 | } | ||
261 | |||
262 | fn foo(u: Un) { | ||
263 | u.<|> | ||
264 | } | ||
265 | ", | ||
266 | ), | ||
267 | @r###" | ||
268 | [ | ||
269 | CompletionItem { | ||
270 | label: "field", | ||
271 | source_range: 67..67, | ||
272 | delete: 67..67, | ||
273 | insert: "field", | ||
274 | kind: Field, | ||
275 | detail: "u8", | ||
276 | }, | ||
277 | CompletionItem { | ||
278 | label: "other", | ||
279 | source_range: 67..67, | ||
280 | delete: 67..67, | ||
281 | insert: "other", | ||
282 | kind: Field, | ||
283 | detail: "u16", | ||
284 | }, | ||
285 | ] | ||
286 | "### | ||
287 | ); | 154 | ); |
288 | } | ||
289 | 155 | ||
290 | #[test] | 156 | check( |
291 | fn test_method_completion() { | 157 | r#" |
292 | assert_debug_snapshot!( | 158 | struct A {} |
293 | do_ref_completion( | 159 | mod m { |
294 | r" | 160 | impl super::A { |
295 | struct A {} | 161 | fn private_method(&self) {} |
296 | impl A { | 162 | pub(super) fn the_method(&self) {} |
297 | fn the_method(&self) {} | 163 | } |
298 | } | 164 | } |
299 | fn foo(a: A) { | 165 | fn foo(a: A) { a.<|> } |
300 | a.<|> | 166 | "#, |
301 | } | 167 | expect![[r#" |
302 | ", | 168 | me the_method() pub(super) fn the_method(&self) |
303 | ), | 169 | "#]], |
304 | @r###" | ||
305 | [ | ||
306 | CompletionItem { | ||
307 | label: "the_method()", | ||
308 | source_range: 71..71, | ||
309 | delete: 71..71, | ||
310 | insert: "the_method()$0", | ||
311 | kind: Method, | ||
312 | lookup: "the_method", | ||
313 | detail: "fn the_method(&self)", | ||
314 | }, | ||
315 | ] | ||
316 | "### | ||
317 | ); | 170 | ); |
318 | } | 171 | } |
319 | 172 | ||
320 | #[test] | 173 | #[test] |
321 | fn test_method_completion_only_fitting_impls() { | 174 | fn test_union_field_completion() { |
322 | assert_debug_snapshot!( | 175 | check( |
323 | do_ref_completion( | 176 | r#" |
324 | r" | 177 | union U { field: u8, other: u16 } |
325 | struct A<T> {} | 178 | fn foo(u: U) { u.<|> } |
326 | impl A<u32> { | 179 | "#, |
327 | fn the_method(&self) {} | 180 | expect![[r#" |
328 | } | 181 | fd field u8 |
329 | impl A<i32> { | 182 | fd other u16 |
330 | fn the_other_method(&self) {} | 183 | "#]], |
331 | } | ||
332 | fn foo(a: A<u32>) { | ||
333 | a.<|> | ||
334 | } | ||
335 | ", | ||
336 | ), | ||
337 | @r###" | ||
338 | [ | ||
339 | CompletionItem { | ||
340 | label: "the_method()", | ||
341 | source_range: 134..134, | ||
342 | delete: 134..134, | ||
343 | insert: "the_method()$0", | ||
344 | kind: Method, | ||
345 | lookup: "the_method", | ||
346 | detail: "fn the_method(&self)", | ||
347 | }, | ||
348 | ] | ||
349 | "### | ||
350 | ); | 184 | ); |
351 | } | 185 | } |
352 | 186 | ||
353 | #[test] | 187 | #[test] |
354 | fn test_method_completion_private() { | 188 | fn test_method_completion_only_fitting_impls() { |
355 | assert_debug_snapshot!( | 189 | check( |
356 | do_ref_completion( | 190 | r#" |
357 | r" | 191 | struct A<T> {} |
358 | struct A {} | 192 | impl A<u32> { |
359 | mod m { | 193 | fn the_method(&self) {} |
360 | impl super::A { | 194 | } |
361 | fn private_method(&self) {} | 195 | impl A<i32> { |
362 | pub(super) fn the_method(&self) {} | 196 | fn the_other_method(&self) {} |
363 | } | 197 | } |
364 | } | 198 | fn foo(a: A<u32>) { a.<|> } |
365 | fn foo(a: A) { | 199 | "#, |
366 | a.<|> | 200 | expect![[r#" |
367 | } | 201 | me the_method() fn the_method(&self) |
368 | ", | 202 | "#]], |
369 | ), | 203 | ) |
370 | @r###" | ||
371 | [ | ||
372 | CompletionItem { | ||
373 | label: "the_method()", | ||
374 | source_range: 147..147, | ||
375 | delete: 147..147, | ||
376 | insert: "the_method()$0", | ||
377 | kind: Method, | ||
378 | lookup: "the_method", | ||
379 | detail: "pub(super) fn the_method(&self)", | ||
380 | }, | ||
381 | ] | ||
382 | "### | ||
383 | ); | ||
384 | } | 204 | } |
385 | 205 | ||
386 | #[test] | 206 | #[test] |
387 | fn test_trait_method_completion() { | 207 | fn test_trait_method_completion() { |
388 | assert_debug_snapshot!( | 208 | check( |
389 | do_ref_completion( | 209 | r#" |
390 | r" | 210 | struct A {} |
391 | struct A {} | 211 | trait Trait { fn the_method(&self); } |
392 | trait Trait { fn the_method(&self); } | 212 | impl Trait for A {} |
393 | impl Trait for A {} | 213 | fn foo(a: A) { a.<|> } |
394 | fn foo(a: A) { | 214 | "#, |
395 | a.<|> | 215 | expect![[r#" |
396 | } | 216 | me the_method() fn the_method(&self) |
397 | ", | 217 | "#]], |
398 | ), | ||
399 | @r###" | ||
400 | [ | ||
401 | CompletionItem { | ||
402 | label: "the_method()", | ||
403 | source_range: 90..90, | ||
404 | delete: 90..90, | ||
405 | insert: "the_method()$0", | ||
406 | kind: Method, | ||
407 | lookup: "the_method", | ||
408 | detail: "fn the_method(&self)", | ||
409 | }, | ||
410 | ] | ||
411 | "### | ||
412 | ); | 218 | ); |
413 | } | 219 | } |
414 | 220 | ||
415 | #[test] | 221 | #[test] |
416 | fn test_trait_method_completion_deduplicated() { | 222 | fn test_trait_method_completion_deduplicated() { |
417 | assert_debug_snapshot!( | 223 | check( |
418 | do_ref_completion( | 224 | r" |
419 | r" | 225 | struct A {} |
420 | struct A {} | 226 | trait Trait { fn the_method(&self); } |
421 | trait Trait { fn the_method(&self); } | 227 | impl<T> Trait for T {} |
422 | impl<T> Trait for T {} | 228 | fn foo(a: &A) { a.<|> } |
423 | fn foo(a: &A) { | 229 | ", |
424 | a.<|> | 230 | expect![[r#" |
425 | } | 231 | me the_method() fn the_method(&self) |
426 | ", | 232 | "#]], |
427 | ), | ||
428 | @r###" | ||
429 | [ | ||
430 | CompletionItem { | ||
431 | label: "the_method()", | ||
432 | source_range: 94..94, | ||
433 | delete: 94..94, | ||
434 | insert: "the_method()$0", | ||
435 | kind: Method, | ||
436 | lookup: "the_method", | ||
437 | detail: "fn the_method(&self)", | ||
438 | }, | ||
439 | ] | ||
440 | "### | ||
441 | ); | 233 | ); |
442 | } | 234 | } |
443 | 235 | ||
444 | #[test] | 236 | #[test] |
445 | fn completes_trait_method_from_other_module() { | 237 | fn completes_trait_method_from_other_module() { |
446 | assert_debug_snapshot!( | 238 | check( |
447 | do_ref_completion( | ||
448 | r" | ||
449 | struct A {} | ||
450 | mod m { | ||
451 | pub trait Trait { fn the_method(&self); } | ||
452 | } | ||
453 | use m::Trait; | ||
454 | impl Trait for A {} | ||
455 | fn foo(a: A) { | ||
456 | a.<|> | ||
457 | } | ||
458 | ", | ||
459 | ), | ||
460 | @r###" | ||
461 | [ | ||
462 | CompletionItem { | ||
463 | label: "the_method()", | ||
464 | source_range: 122..122, | ||
465 | delete: 122..122, | ||
466 | insert: "the_method()$0", | ||
467 | kind: Method, | ||
468 | lookup: "the_method", | ||
469 | detail: "fn the_method(&self)", | ||
470 | }, | ||
471 | ] | ||
472 | "### | ||
473 | ); | ||
474 | } | ||
475 | |||
476 | #[test] | ||
477 | fn test_no_non_self_method() { | ||
478 | assert_debug_snapshot!( | ||
479 | do_ref_completion( | ||
480 | r" | 239 | r" |
481 | struct A {} | 240 | struct A {} |
482 | impl A { | 241 | mod m { |
483 | fn the_method() {} | 242 | pub trait Trait { fn the_method(&self); } |
484 | } | 243 | } |
485 | fn foo(a: A) { | 244 | use m::Trait; |
486 | a.<|> | 245 | impl Trait for A {} |
487 | } | 246 | fn foo(a: A) { a.<|> } |
488 | ", | 247 | ", |
489 | ), | 248 | expect![[r#" |
490 | @"[]" | 249 | me the_method() fn the_method(&self) |
250 | "#]], | ||
491 | ); | 251 | ); |
492 | } | 252 | } |
493 | 253 | ||
494 | #[test] | 254 | #[test] |
495 | fn test_method_attr_filtering() { | 255 | fn test_no_non_self_method() { |
496 | assert_debug_snapshot!( | 256 | check( |
497 | do_ref_completion( | 257 | r#" |
498 | r" | 258 | struct A {} |
499 | struct A {} | 259 | impl A { |
500 | impl A { | 260 | fn the_method() {} |
501 | #[inline] | 261 | } |
502 | fn the_method(&self) { | 262 | fn foo(a: A) { |
503 | let x = 1; | 263 | a.<|> |
504 | let y = 2; | 264 | } |
505 | } | 265 | "#, |
506 | } | 266 | expect![[""]], |
507 | fn foo(a: A) { | ||
508 | a.<|> | ||
509 | } | ||
510 | ", | ||
511 | ), | ||
512 | @r###" | ||
513 | [ | ||
514 | CompletionItem { | ||
515 | label: "the_method()", | ||
516 | source_range: 128..128, | ||
517 | delete: 128..128, | ||
518 | insert: "the_method()$0", | ||
519 | kind: Method, | ||
520 | lookup: "the_method", | ||
521 | detail: "fn the_method(&self)", | ||
522 | }, | ||
523 | ] | ||
524 | "### | ||
525 | ); | 267 | ); |
526 | } | 268 | } |
527 | 269 | ||
528 | #[test] | 270 | #[test] |
529 | fn test_tuple_field_completion() { | 271 | fn test_tuple_field_completion() { |
530 | assert_debug_snapshot!( | 272 | check( |
531 | do_ref_completion( | 273 | r#" |
532 | r" | 274 | fn foo() { |
533 | fn foo() { | 275 | let b = (0, 3.14); |
534 | let b = (0, 3.14); | 276 | b.<|> |
535 | b.<|> | 277 | } |
536 | } | 278 | "#, |
537 | ", | 279 | expect![[r#" |
538 | ), | 280 | fd 0 i32 |
539 | @r###" | 281 | fd 1 f64 |
540 | [ | 282 | "#]], |
541 | CompletionItem { | 283 | ) |
542 | label: "0", | ||
543 | source_range: 38..38, | ||
544 | delete: 38..38, | ||
545 | insert: "0", | ||
546 | kind: Field, | ||
547 | detail: "i32", | ||
548 | }, | ||
549 | CompletionItem { | ||
550 | label: "1", | ||
551 | source_range: 38..38, | ||
552 | delete: 38..38, | ||
553 | insert: "1", | ||
554 | kind: Field, | ||
555 | detail: "f64", | ||
556 | }, | ||
557 | ] | ||
558 | "### | ||
559 | ); | ||
560 | } | 284 | } |
561 | 285 | ||
562 | #[test] | 286 | #[test] |
563 | fn test_tuple_field_inference() { | 287 | fn test_tuple_field_inference() { |
564 | assert_debug_snapshot!( | 288 | check( |
565 | do_ref_completion( | 289 | r#" |
566 | r" | 290 | pub struct S; |
567 | pub struct S; | 291 | impl S { pub fn blah(&self) {} } |
568 | impl S { | ||
569 | pub fn blah(&self) {} | ||
570 | } | ||
571 | 292 | ||
572 | struct T(S); | 293 | struct T(S); |
573 | 294 | ||
574 | impl T { | 295 | impl T { |
575 | fn foo(&self) { | 296 | fn foo(&self) { |
576 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float | 297 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float |
577 | self.0.a<|> | 298 | self.0.a<|> |
578 | } | ||
579 | } | ||
580 | ", | ||
581 | ), | ||
582 | @r###" | ||
583 | [ | ||
584 | CompletionItem { | ||
585 | label: "blah()", | ||
586 | source_range: 190..191, | ||
587 | delete: 190..191, | ||
588 | insert: "blah()$0", | ||
589 | kind: Method, | ||
590 | lookup: "blah", | ||
591 | detail: "pub fn blah(&self)", | ||
592 | }, | ||
593 | ] | ||
594 | "### | ||
595 | ); | ||
596 | } | 299 | } |
597 | 300 | } | |
598 | #[test] | 301 | "#, |
599 | fn test_completion_works_in_consts() { | 302 | expect![[r#" |
600 | assert_debug_snapshot!( | 303 | me blah() pub fn blah(&self) |
601 | do_ref_completion( | 304 | "#]], |
602 | r" | ||
603 | struct A { the_field: u32 } | ||
604 | const X: u32 = { | ||
605 | A { the_field: 92 }.<|> | ||
606 | }; | ||
607 | ", | ||
608 | ), | ||
609 | @r###" | ||
610 | [ | ||
611 | CompletionItem { | ||
612 | label: "the_field", | ||
613 | source_range: 69..69, | ||
614 | delete: 69..69, | ||
615 | insert: "the_field", | ||
616 | kind: Field, | ||
617 | detail: "u32", | ||
618 | }, | ||
619 | ] | ||
620 | "### | ||
621 | ); | 305 | ); |
622 | } | 306 | } |
623 | 307 | ||
624 | #[test] | 308 | #[test] |
625 | fn test_completion_await_impls_future() { | 309 | fn test_completion_works_in_consts() { |
626 | assert_debug_snapshot!( | 310 | check( |
627 | do_completion( | 311 | r#" |
628 | r###" | 312 | struct A { the_field: u32 } |
629 | //- /main.rs | 313 | const X: u32 = { |
630 | use std::future::*; | 314 | A { the_field: 92 }.<|> |
631 | struct A {} | 315 | }; |
632 | impl Future for A {} | 316 | "#, |
633 | fn foo(a: A) { | 317 | expect![[r#" |
634 | a.<|> | 318 | fd the_field u32 |
635 | } | 319 | "#]], |
636 | |||
637 | //- /std/lib.rs | ||
638 | pub mod future { | ||
639 | #[lang = "future_trait"] | ||
640 | pub trait Future {} | ||
641 | } | ||
642 | "###, CompletionKind::Keyword), | ||
643 | @r###" | ||
644 | [ | ||
645 | CompletionItem { | ||
646 | label: "await", | ||
647 | source_range: 74..74, | ||
648 | delete: 74..74, | ||
649 | insert: "await", | ||
650 | detail: "expr.await", | ||
651 | }, | ||
652 | ] | ||
653 | "### | ||
654 | ) | ||
655 | } | ||
656 | |||
657 | #[test] | ||
658 | fn test_super_super_completion() { | ||
659 | assert_debug_snapshot!( | ||
660 | do_ref_completion( | ||
661 | r" | ||
662 | mod a { | ||
663 | const A: usize = 0; | ||
664 | |||
665 | mod b { | ||
666 | const B: usize = 0; | ||
667 | |||
668 | mod c { | ||
669 | use super::super::<|> | ||
670 | } | ||
671 | } | ||
672 | } | ||
673 | ", | ||
674 | ), | ||
675 | @r###" | ||
676 | [ | ||
677 | CompletionItem { | ||
678 | label: "A", | ||
679 | source_range: 120..120, | ||
680 | delete: 120..120, | ||
681 | insert: "A", | ||
682 | kind: Const, | ||
683 | }, | ||
684 | CompletionItem { | ||
685 | label: "b", | ||
686 | source_range: 120..120, | ||
687 | delete: 120..120, | ||
688 | insert: "b", | ||
689 | kind: Module, | ||
690 | }, | ||
691 | ] | ||
692 | "### | ||
693 | ); | 320 | ); |
694 | } | 321 | } |
695 | 322 | ||
696 | #[test] | 323 | #[test] |
697 | fn works_in_simple_macro_1() { | 324 | fn works_in_simple_macro_1() { |
698 | assert_debug_snapshot!( | 325 | check( |
699 | do_ref_completion( | 326 | r#" |
700 | r" | 327 | macro_rules! m { ($e:expr) => { $e } } |
701 | macro_rules! m { ($e:expr) => { $e } } | 328 | struct A { the_field: u32 } |
702 | struct A { the_field: u32 } | 329 | fn foo(a: A) { |
703 | fn foo(a: A) { | 330 | m!(a.x<|>) |
704 | m!(a.x<|>) | 331 | } |
705 | } | 332 | "#, |
706 | ", | 333 | expect![[r#" |
707 | ), | 334 | fd the_field u32 |
708 | @r###" | 335 | "#]], |
709 | [ | ||
710 | CompletionItem { | ||
711 | label: "the_field", | ||
712 | source_range: 91..92, | ||
713 | delete: 91..92, | ||
714 | insert: "the_field", | ||
715 | kind: Field, | ||
716 | detail: "u32", | ||
717 | }, | ||
718 | ] | ||
719 | "### | ||
720 | ); | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn works_in_simple_macro_recursive() { | ||
725 | assert_debug_snapshot!( | ||
726 | do_ref_completion( | ||
727 | r" | ||
728 | macro_rules! m { ($e:expr) => { $e } } | ||
729 | struct A { the_field: u32 } | ||
730 | fn foo(a: A) { | ||
731 | m!(a.x<|>) | ||
732 | } | ||
733 | ", | ||
734 | ), | ||
735 | @r###" | ||
736 | [ | ||
737 | CompletionItem { | ||
738 | label: "the_field", | ||
739 | source_range: 91..92, | ||
740 | delete: 91..92, | ||
741 | insert: "the_field", | ||
742 | kind: Field, | ||
743 | detail: "u32", | ||
744 | }, | ||
745 | ] | ||
746 | "### | ||
747 | ); | 336 | ); |
748 | } | 337 | } |
749 | 338 | ||
750 | #[test] | 339 | #[test] |
751 | fn works_in_simple_macro_2() { | 340 | fn works_in_simple_macro_2() { |
752 | // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery | 341 | // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery |
753 | assert_debug_snapshot!( | 342 | check( |
754 | do_ref_completion( | 343 | r#" |
755 | r" | 344 | macro_rules! m { ($e:expr) => { $e } } |
756 | macro_rules! m { ($e:expr) => { $e } } | 345 | struct A { the_field: u32 } |
757 | struct A { the_field: u32 } | 346 | fn foo(a: A) { |
758 | fn foo(a: A) { | 347 | m!(a.<|>) |
759 | m!(a.<|>) | 348 | } |
760 | } | 349 | "#, |
761 | ", | 350 | expect![[r#" |
762 | ), | 351 | fd the_field u32 |
763 | @r###" | 352 | "#]], |
764 | [ | ||
765 | CompletionItem { | ||
766 | label: "the_field", | ||
767 | source_range: 91..91, | ||
768 | delete: 91..91, | ||
769 | insert: "the_field", | ||
770 | kind: Field, | ||
771 | detail: "u32", | ||
772 | }, | ||
773 | ] | ||
774 | "### | ||
775 | ); | 353 | ); |
776 | } | 354 | } |
777 | 355 | ||
778 | #[test] | 356 | #[test] |
779 | fn works_in_simple_macro_recursive_1() { | 357 | fn works_in_simple_macro_recursive_1() { |
780 | assert_debug_snapshot!( | 358 | check( |
781 | do_ref_completion( | 359 | r#" |
782 | r" | 360 | macro_rules! m { ($e:expr) => { $e } } |
783 | macro_rules! m { ($e:expr) => { $e } } | 361 | struct A { the_field: u32 } |
784 | struct A { the_field: u32 } | 362 | fn foo(a: A) { |
785 | fn foo(a: A) { | 363 | m!(m!(m!(a.x<|>))) |
786 | m!(m!(m!(a.x<|>))) | 364 | } |
787 | } | 365 | "#, |
788 | ", | 366 | expect![[r#" |
789 | ), | 367 | fd the_field u32 |
790 | @r###" | 368 | "#]], |
791 | [ | ||
792 | CompletionItem { | ||
793 | label: "the_field", | ||
794 | source_range: 97..98, | ||
795 | delete: 97..98, | ||
796 | insert: "the_field", | ||
797 | kind: Field, | ||
798 | detail: "u32", | ||
799 | }, | ||
800 | ] | ||
801 | "### | ||
802 | ); | 369 | ); |
803 | } | 370 | } |
804 | 371 | ||
805 | #[test] | 372 | #[test] |
806 | fn macro_expansion_resilient() { | 373 | fn macro_expansion_resilient() { |
807 | assert_debug_snapshot!( | 374 | check( |
808 | do_ref_completion( | 375 | r#" |
809 | r" | 376 | macro_rules! dbg { |
810 | macro_rules! dbg { | 377 | () => {}; |
811 | () => {}; | 378 | ($val:expr) => { |
812 | ($val:expr) => { | 379 | match $val { tmp => { tmp } } |
813 | match $val { tmp => { tmp } } | 380 | }; |
814 | }; | 381 | // Trailing comma with single argument is ignored |
815 | // Trailing comma with single argument is ignored | 382 | ($val:expr,) => { $crate::dbg!($val) }; |
816 | ($val:expr,) => { $crate::dbg!($val) }; | 383 | ($($val:expr),+ $(,)?) => { |
817 | ($($val:expr),+ $(,)?) => { | 384 | ($($crate::dbg!($val)),+,) |
818 | ($($crate::dbg!($val)),+,) | 385 | }; |
819 | }; | 386 | } |
820 | } | 387 | struct A { the_field: u32 } |
821 | struct A { the_field: u32 } | 388 | fn foo(a: A) { |
822 | fn foo(a: A) { | 389 | dbg!(a.<|>) |
823 | dbg!(a.<|>) | 390 | } |
824 | } | 391 | "#, |
825 | ", | 392 | expect![[r#" |
826 | ), | 393 | fd the_field u32 |
827 | @r###" | 394 | "#]], |
828 | [ | ||
829 | CompletionItem { | ||
830 | label: "the_field", | ||
831 | source_range: 327..327, | ||
832 | delete: 327..327, | ||
833 | insert: "the_field", | ||
834 | kind: Field, | ||
835 | detail: "u32", | ||
836 | }, | ||
837 | ] | ||
838 | "### | ||
839 | ); | 395 | ); |
840 | } | 396 | } |
841 | 397 | ||
842 | #[test] | 398 | #[test] |
843 | fn test_method_completion_3547() { | 399 | fn test_method_completion_issue_3547() { |
844 | assert_debug_snapshot!( | 400 | check( |
845 | do_ref_completion( | 401 | r#" |
846 | r" | 402 | struct HashSet<T> {} |
847 | struct HashSet<T> {} | 403 | impl<T> HashSet<T> { |
848 | impl<T> HashSet<T> { | 404 | pub fn the_method(&self) {} |
849 | pub fn the_method(&self) {} | 405 | } |
850 | } | 406 | fn foo() { |
851 | fn foo() { | 407 | let s: HashSet<_>; |
852 | let s: HashSet<_>; | 408 | s.<|> |
853 | s.<|> | 409 | } |
854 | } | 410 | "#, |
855 | ", | 411 | expect![[r#" |
856 | ), | 412 | me the_method() pub fn the_method(&self) |
857 | @r###" | 413 | "#]], |
858 | [ | ||
859 | CompletionItem { | ||
860 | label: "the_method()", | ||
861 | source_range: 116..116, | ||
862 | delete: 116..116, | ||
863 | insert: "the_method()$0", | ||
864 | kind: Method, | ||
865 | lookup: "the_method", | ||
866 | detail: "pub fn the_method(&self)", | ||
867 | }, | ||
868 | ] | ||
869 | "### | ||
870 | ); | 414 | ); |
871 | } | 415 | } |
872 | } | 416 | } |
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 086b917ce..340d57a49 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs | |||
@@ -35,6 +35,19 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
35 | } | 35 | } |
36 | _ => {} | 36 | _ => {} |
37 | } | 37 | } |
38 | |||
39 | // Suggest .await syntax for types that implement Future trait | ||
40 | if let Some(receiver) = &ctx.dot_receiver { | ||
41 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | ||
42 | if ty.impls_future(ctx.db) { | ||
43 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") | ||
44 | .kind(CompletionItemKind::Keyword) | ||
45 | .detail("expr.await") | ||
46 | .insert_text("await") | ||
47 | .add_to(acc); | ||
48 | } | ||
49 | }; | ||
50 | } | ||
38 | } | 51 | } |
39 | 52 | ||
40 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 53 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -490,4 +503,26 @@ Some multi-line comment<|> | |||
490 | expect![[""]], | 503 | expect![[""]], |
491 | ); | 504 | ); |
492 | } | 505 | } |
506 | |||
507 | #[test] | ||
508 | fn test_completion_await_impls_future() { | ||
509 | check( | ||
510 | r#" | ||
511 | //- /main.rs | ||
512 | use std::future::*; | ||
513 | struct A {} | ||
514 | impl Future for A {} | ||
515 | fn foo(a: A) { a.<|> } | ||
516 | |||
517 | //- /std/lib.rs | ||
518 | pub mod future { | ||
519 | #[lang = "future_trait"] | ||
520 | pub trait Future {} | ||
521 | } | ||
522 | "#, | ||
523 | expect![[r#" | ||
524 | kw await expr.await | ||
525 | "#]], | ||
526 | ) | ||
527 | } | ||
493 | } | 528 | } |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index f133ce3ce..a16866cd2 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -1206,6 +1206,45 @@ mod tests { | |||
1206 | } | 1206 | } |
1207 | 1207 | ||
1208 | #[test] | 1208 | #[test] |
1209 | fn test_super_super_completion() { | ||
1210 | assert_debug_snapshot!( | ||
1211 | do_reference_completion( | ||
1212 | r" | ||
1213 | mod a { | ||
1214 | const A: usize = 0; | ||
1215 | |||
1216 | mod b { | ||
1217 | const B: usize = 0; | ||
1218 | |||
1219 | mod c { | ||
1220 | use super::super::<|> | ||
1221 | } | ||
1222 | } | ||
1223 | } | ||
1224 | ", | ||
1225 | ), | ||
1226 | @r###" | ||
1227 | [ | ||
1228 | CompletionItem { | ||
1229 | label: "A", | ||
1230 | source_range: 120..120, | ||
1231 | delete: 120..120, | ||
1232 | insert: "A", | ||
1233 | kind: Const, | ||
1234 | }, | ||
1235 | CompletionItem { | ||
1236 | label: "b", | ||
1237 | source_range: 120..120, | ||
1238 | delete: 120..120, | ||
1239 | insert: "b", | ||
1240 | kind: Module, | ||
1241 | }, | ||
1242 | ] | ||
1243 | "### | ||
1244 | ); | ||
1245 | } | ||
1246 | |||
1247 | #[test] | ||
1209 | fn completes_reexported_items_under_correct_name() { | 1248 | fn completes_reexported_items_under_correct_name() { |
1210 | assert_debug_snapshot!( | 1249 | assert_debug_snapshot!( |
1211 | do_reference_completion( | 1250 | do_reference_completion( |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 4db371d57..477d6f6f6 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -95,7 +95,7 @@ impl fmt::Debug for CompletionItem { | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | #[derive(Debug, Clone, Copy)] | 98 | #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] |
99 | pub enum CompletionScore { | 99 | pub enum CompletionScore { |
100 | /// If only type match | 100 | /// If only type match |
101 | TypeMatch, | 101 | TypeMatch, |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index fd12673b2..dc391c46b 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | //! It also handles scoring (sorting) completions. | ||
2 | 3 | ||
3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; | 4 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; |
4 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
@@ -330,14 +331,14 @@ pub(crate) fn compute_score( | |||
330 | // FIXME: this should not fall back to string equality. | 331 | // FIXME: this should not fall back to string equality. |
331 | let ty = &ty.display(ctx.db).to_string(); | 332 | let ty = &ty.display(ctx.db).to_string(); |
332 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { | 333 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { |
333 | mark::hit!(test_struct_field_completion_in_record_lit); | 334 | mark::hit!(record_field_type_match); |
334 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; | 335 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; |
335 | ( | 336 | ( |
336 | struct_field.name(ctx.db).to_string(), | 337 | struct_field.name(ctx.db).to_string(), |
337 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | 338 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), |
338 | ) | 339 | ) |
339 | } else if let Some(active_parameter) = &ctx.active_parameter { | 340 | } else if let Some(active_parameter) = &ctx.active_parameter { |
340 | mark::hit!(test_struct_field_completion_in_func_call); | 341 | mark::hit!(active_param_type_match); |
341 | (active_parameter.name.clone(), active_parameter.ty.clone()) | 342 | (active_parameter.name.clone(), active_parameter.ty.clone()) |
342 | } else { | 343 | } else { |
343 | return None; | 344 | return None; |
@@ -461,174 +462,254 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s | |||
461 | 462 | ||
462 | #[cfg(test)] | 463 | #[cfg(test)] |
463 | mod tests { | 464 | mod tests { |
464 | use insta::assert_debug_snapshot; | 465 | use std::cmp::Reverse; |
466 | |||
467 | use expect::{expect, Expect}; | ||
465 | use test_utils::mark; | 468 | use test_utils::mark; |
466 | 469 | ||
467 | use crate::completion::{ | 470 | use crate::{ |
468 | test_utils::{check_edit, check_edit_with_config, do_completion}, | 471 | completion::{ |
469 | CompletionConfig, CompletionItem, CompletionKind, | 472 | test_utils::{ |
473 | check_edit, check_edit_with_config, do_completion, get_all_completion_items, | ||
474 | }, | ||
475 | CompletionConfig, CompletionKind, | ||
476 | }, | ||
477 | CompletionScore, | ||
470 | }; | 478 | }; |
471 | 479 | ||
472 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { | 480 | fn check(ra_fixture: &str, expect: Expect) { |
473 | do_completion(ra_fixture, CompletionKind::Reference) | 481 | let actual = do_completion(ra_fixture, CompletionKind::Reference); |
482 | expect.assert_debug_eq(&actual); | ||
483 | } | ||
484 | |||
485 | fn check_scores(ra_fixture: &str, expect: Expect) { | ||
486 | fn display_score(score: Option<CompletionScore>) -> &'static str { | ||
487 | match score { | ||
488 | Some(CompletionScore::TypeMatch) => "[type]", | ||
489 | Some(CompletionScore::TypeAndNameMatch) => "[type+name]", | ||
490 | None => "[]".into(), | ||
491 | } | ||
492 | } | ||
493 | |||
494 | let mut completions = get_all_completion_items(ra_fixture, &CompletionConfig::default()); | ||
495 | completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); | ||
496 | let actual = completions | ||
497 | .into_iter() | ||
498 | .filter(|it| it.completion_kind == CompletionKind::Reference) | ||
499 | .map(|it| { | ||
500 | let tag = it.kind().unwrap().tag(); | ||
501 | let score = display_score(it.score()); | ||
502 | format!("{} {} {}\n", tag, it.label(), score) | ||
503 | }) | ||
504 | .collect::<String>(); | ||
505 | expect.assert_eq(&actual); | ||
474 | } | 506 | } |
475 | 507 | ||
476 | #[test] | 508 | #[test] |
477 | fn enum_detail_includes_names_for_record() { | 509 | fn enum_detail_includes_record_fields() { |
478 | assert_debug_snapshot!( | 510 | check( |
479 | do_reference_completion( | ||
480 | r#" | 511 | r#" |
481 | enum Foo { | 512 | enum Foo { Foo { x: i32, y: i32 } } |
482 | Foo {x: i32, y: i32} | ||
483 | } | ||
484 | 513 | ||
485 | fn main() { Foo::Fo<|> } | 514 | fn main() { Foo::Fo<|> } |
486 | "#, | 515 | "#, |
487 | ), | 516 | expect![[r#" |
488 | @r###" | 517 | [ |
489 | [ | 518 | CompletionItem { |
490 | CompletionItem { | 519 | label: "Foo", |
491 | label: "Foo", | 520 | source_range: 54..56, |
492 | source_range: 56..58, | 521 | delete: 54..56, |
493 | delete: 56..58, | 522 | insert: "Foo", |
494 | insert: "Foo", | 523 | kind: EnumVariant, |
495 | kind: EnumVariant, | 524 | detail: "{ x: i32, y: i32 }", |
496 | detail: "{ x: i32, y: i32 }", | 525 | }, |
497 | }, | 526 | ] |
498 | ] | 527 | "#]], |
499 | "### | ||
500 | ); | 528 | ); |
501 | } | 529 | } |
502 | 530 | ||
503 | #[test] | 531 | #[test] |
504 | fn enum_detail_doesnt_include_names_for_tuple() { | 532 | fn enum_detail_doesnt_include_tuple_fields() { |
505 | assert_debug_snapshot!( | 533 | check( |
506 | do_reference_completion( | ||
507 | r#" | 534 | r#" |
508 | enum Foo { | 535 | enum Foo { Foo (i32, i32) } |
509 | Foo (i32, i32) | ||
510 | } | ||
511 | 536 | ||
512 | fn main() { Foo::Fo<|> } | 537 | fn main() { Foo::Fo<|> } |
513 | "#, | 538 | "#, |
514 | ), | 539 | expect![[r#" |
515 | @r###" | 540 | [ |
516 | [ | 541 | CompletionItem { |
517 | CompletionItem { | 542 | label: "Foo(…)", |
518 | label: "Foo(…)", | 543 | source_range: 46..48, |
519 | source_range: 50..52, | 544 | delete: 46..48, |
520 | delete: 50..52, | 545 | insert: "Foo($0)", |
521 | insert: "Foo($0)", | 546 | kind: EnumVariant, |
522 | kind: EnumVariant, | 547 | lookup: "Foo", |
523 | lookup: "Foo", | 548 | detail: "(i32, i32)", |
524 | detail: "(i32, i32)", | 549 | trigger_call_info: true, |
525 | trigger_call_info: true, | 550 | }, |
526 | }, | 551 | ] |
527 | ] | 552 | "#]], |
528 | "### | ||
529 | ); | 553 | ); |
530 | } | 554 | } |
531 | 555 | ||
532 | #[test] | 556 | #[test] |
533 | fn enum_detail_just_parentheses_for_unit() { | 557 | fn enum_detail_just_parentheses_for_unit() { |
534 | assert_debug_snapshot!( | 558 | check( |
535 | do_reference_completion( | ||
536 | r#" | 559 | r#" |
537 | enum Foo { | 560 | enum Foo { Foo } |
538 | Foo | ||
539 | } | ||
540 | 561 | ||
541 | fn main() { Foo::Fo<|> } | 562 | fn main() { Foo::Fo<|> } |
542 | "#, | 563 | "#, |
543 | ), | 564 | expect![[r#" |
544 | @r###" | 565 | [ |
545 | [ | 566 | CompletionItem { |
546 | CompletionItem { | 567 | label: "Foo", |
547 | label: "Foo", | 568 | source_range: 35..37, |
548 | source_range: 39..41, | 569 | delete: 35..37, |
549 | delete: 39..41, | 570 | insert: "Foo", |
550 | insert: "Foo", | 571 | kind: EnumVariant, |
551 | kind: EnumVariant, | 572 | detail: "()", |
552 | detail: "()", | 573 | }, |
553 | }, | 574 | ] |
554 | ] | 575 | "#]], |
555 | "### | ||
556 | ); | 576 | ); |
557 | } | 577 | } |
558 | 578 | ||
559 | #[test] | 579 | #[test] |
560 | fn sets_deprecated_flag_in_completion_items() { | 580 | fn sets_deprecated_flag_in_completion_items() { |
561 | assert_debug_snapshot!( | 581 | check( |
562 | do_reference_completion( | 582 | r#" |
563 | r#" | 583 | #[deprecated] |
564 | #[deprecated] | 584 | fn something_deprecated() {} |
565 | fn something_deprecated() {} | 585 | #[deprecated(since = "1.0.0")] |
566 | 586 | fn something_else_deprecated() {} | |
567 | #[deprecated(since = "1.0.0")] | 587 | |
568 | fn something_else_deprecated() {} | 588 | fn main() { som<|> } |
569 | 589 | "#, | |
570 | fn main() { som<|> } | 590 | expect![[r#" |
571 | "#, | 591 | [ |
572 | ), | 592 | CompletionItem { |
573 | @r###" | 593 | label: "main()", |
574 | [ | 594 | source_range: 121..124, |
575 | CompletionItem { | 595 | delete: 121..124, |
576 | label: "main()", | 596 | insert: "main()$0", |
577 | source_range: 122..125, | 597 | kind: Function, |
578 | delete: 122..125, | 598 | lookup: "main", |
579 | insert: "main()$0", | 599 | detail: "fn main()", |
580 | kind: Function, | 600 | }, |
581 | lookup: "main", | 601 | CompletionItem { |
582 | detail: "fn main()", | 602 | label: "something_deprecated()", |
583 | }, | 603 | source_range: 121..124, |
584 | CompletionItem { | 604 | delete: 121..124, |
585 | label: "something_deprecated()", | 605 | insert: "something_deprecated()$0", |
586 | source_range: 122..125, | 606 | kind: Function, |
587 | delete: 122..125, | 607 | lookup: "something_deprecated", |
588 | insert: "something_deprecated()$0", | 608 | detail: "fn something_deprecated()", |
589 | kind: Function, | 609 | deprecated: true, |
590 | lookup: "something_deprecated", | 610 | }, |
591 | detail: "fn something_deprecated()", | 611 | CompletionItem { |
592 | deprecated: true, | 612 | label: "something_else_deprecated()", |
593 | }, | 613 | source_range: 121..124, |
594 | CompletionItem { | 614 | delete: 121..124, |
595 | label: "something_else_deprecated()", | 615 | insert: "something_else_deprecated()$0", |
596 | source_range: 122..125, | 616 | kind: Function, |
597 | delete: 122..125, | 617 | lookup: "something_else_deprecated", |
598 | insert: "something_else_deprecated()$0", | 618 | detail: "fn something_else_deprecated()", |
599 | kind: Function, | 619 | deprecated: true, |
600 | lookup: "something_else_deprecated", | 620 | }, |
601 | detail: "fn something_else_deprecated()", | 621 | ] |
602 | deprecated: true, | 622 | "#]], |
603 | }, | 623 | ); |
604 | ] | 624 | |
605 | "### | 625 | check( |
626 | r#" | ||
627 | struct A { #[deprecated] the_field: u32 } | ||
628 | fn foo() { A { the<|> } } | ||
629 | "#, | ||
630 | expect![[r#" | ||
631 | [ | ||
632 | CompletionItem { | ||
633 | label: "the_field", | ||
634 | source_range: 57..60, | ||
635 | delete: 57..60, | ||
636 | insert: "the_field", | ||
637 | kind: Field, | ||
638 | detail: "u32", | ||
639 | deprecated: true, | ||
640 | }, | ||
641 | ] | ||
642 | "#]], | ||
606 | ); | 643 | ); |
644 | } | ||
607 | 645 | ||
608 | assert_debug_snapshot!(do_reference_completion( | 646 | #[test] |
647 | fn renders_docs() { | ||
648 | check( | ||
609 | r#" | 649 | r#" |
610 | struct A { | 650 | struct S { |
611 | #[deprecated] | 651 | /// Field docs |
612 | the_field: u32, | 652 | foo: |
613 | } | 653 | } |
614 | fn foo() { | 654 | impl S { |
615 | A { the<|> } | 655 | /// Method docs |
656 | fn bar(self) { self.<|> } | ||
657 | }"#, | ||
658 | expect![[r#" | ||
659 | [ | ||
660 | CompletionItem { | ||
661 | label: "bar()", | ||
662 | source_range: 94..94, | ||
663 | delete: 94..94, | ||
664 | insert: "bar()$0", | ||
665 | kind: Method, | ||
666 | lookup: "bar", | ||
667 | detail: "fn bar(self)", | ||
668 | documentation: Documentation( | ||
669 | "Method docs", | ||
670 | ), | ||
671 | }, | ||
672 | CompletionItem { | ||
673 | label: "foo", | ||
674 | source_range: 94..94, | ||
675 | delete: 94..94, | ||
676 | insert: "foo", | ||
677 | kind: Field, | ||
678 | detail: "{unknown}", | ||
679 | documentation: Documentation( | ||
680 | "Field docs", | ||
681 | ), | ||
682 | }, | ||
683 | ] | ||
684 | "#]], | ||
685 | ) | ||
686 | } | ||
687 | |||
688 | #[test] | ||
689 | fn dont_render_attrs() { | ||
690 | check( | ||
691 | r#" | ||
692 | struct S; | ||
693 | impl S { | ||
694 | #[inline] | ||
695 | fn the_method(&self) { } | ||
616 | } | 696 | } |
697 | fn foo(s: S) { s.<|> } | ||
617 | "#, | 698 | "#, |
618 | ), | 699 | expect![[r#" |
619 | @r###" | 700 | [ |
620 | [ | 701 | CompletionItem { |
621 | CompletionItem { | 702 | label: "the_method()", |
622 | label: "the_field", | 703 | source_range: 81..81, |
623 | source_range: 69..72, | 704 | delete: 81..81, |
624 | delete: 69..72, | 705 | insert: "the_method()$0", |
625 | insert: "the_field", | 706 | kind: Method, |
626 | kind: Field, | 707 | lookup: "the_method", |
627 | detail: "u32", | 708 | detail: "fn the_method(&self)", |
628 | deprecated: true, | 709 | }, |
629 | }, | 710 | ] |
630 | ] | 711 | "#]], |
631 | "###); | 712 | ) |
632 | } | 713 | } |
633 | 714 | ||
634 | #[test] | 715 | #[test] |
@@ -844,466 +925,158 @@ fn f(foo: &Foo) { foo.foo(); } | |||
844 | #[test] | 925 | #[test] |
845 | fn inserts_angle_brackets_for_generics() { | 926 | fn inserts_angle_brackets_for_generics() { |
846 | mark::check!(inserts_angle_brackets_for_generics); | 927 | mark::check!(inserts_angle_brackets_for_generics); |
847 | assert_debug_snapshot!( | 928 | check_edit( |
848 | do_reference_completion( | 929 | "Vec", |
849 | r" | 930 | r#" |
850 | struct Vec<T> {} | 931 | struct Vec<T> {} |
851 | fn foo(xs: Ve<|>) | 932 | fn foo(xs: Ve<|>) |
852 | " | 933 | "#, |
853 | ), | 934 | r#" |
854 | @r###" | 935 | struct Vec<T> {} |
855 | [ | 936 | fn foo(xs: Vec<$0>) |
856 | CompletionItem { | 937 | "#, |
857 | label: "Vec<…>", | ||
858 | source_range: 28..30, | ||
859 | delete: 28..30, | ||
860 | insert: "Vec<$0>", | ||
861 | kind: Struct, | ||
862 | lookup: "Vec", | ||
863 | }, | ||
864 | CompletionItem { | ||
865 | label: "foo(…)", | ||
866 | source_range: 28..30, | ||
867 | delete: 28..30, | ||
868 | insert: "foo(${1:xs})$0", | ||
869 | kind: Function, | ||
870 | lookup: "foo", | ||
871 | detail: "fn foo(xs: Ve)", | ||
872 | trigger_call_info: true, | ||
873 | }, | ||
874 | ] | ||
875 | "### | ||
876 | ); | 938 | ); |
877 | assert_debug_snapshot!( | 939 | check_edit( |
878 | do_reference_completion( | 940 | "Vec", |
879 | r" | 941 | r#" |
880 | type Vec<T> = (T,); | 942 | type Vec<T> = (T,); |
881 | fn foo(xs: Ve<|>) | 943 | fn foo(xs: Ve<|>) |
882 | " | 944 | "#, |
883 | ), | 945 | r#" |
884 | @r###" | 946 | type Vec<T> = (T,); |
885 | [ | 947 | fn foo(xs: Vec<$0>) |
886 | CompletionItem { | 948 | "#, |
887 | label: "Vec<…>", | ||
888 | source_range: 31..33, | ||
889 | delete: 31..33, | ||
890 | insert: "Vec<$0>", | ||
891 | kind: TypeAlias, | ||
892 | lookup: "Vec", | ||
893 | }, | ||
894 | CompletionItem { | ||
895 | label: "foo(…)", | ||
896 | source_range: 31..33, | ||
897 | delete: 31..33, | ||
898 | insert: "foo(${1:xs})$0", | ||
899 | kind: Function, | ||
900 | lookup: "foo", | ||
901 | detail: "fn foo(xs: Ve)", | ||
902 | trigger_call_info: true, | ||
903 | }, | ||
904 | ] | ||
905 | "### | ||
906 | ); | 949 | ); |
907 | assert_debug_snapshot!( | 950 | check_edit( |
908 | do_reference_completion( | 951 | "Vec", |
909 | r" | 952 | r#" |
910 | struct Vec<T = i128> {} | 953 | struct Vec<T = i128> {} |
911 | fn foo(xs: Ve<|>) | 954 | fn foo(xs: Ve<|>) |
912 | " | 955 | "#, |
913 | ), | 956 | r#" |
914 | @r###" | 957 | struct Vec<T = i128> {} |
915 | [ | 958 | fn foo(xs: Vec) |
916 | CompletionItem { | 959 | "#, |
917 | label: "Vec", | ||
918 | source_range: 35..37, | ||
919 | delete: 35..37, | ||
920 | insert: "Vec", | ||
921 | kind: Struct, | ||
922 | }, | ||
923 | CompletionItem { | ||
924 | label: "foo(…)", | ||
925 | source_range: 35..37, | ||
926 | delete: 35..37, | ||
927 | insert: "foo(${1:xs})$0", | ||
928 | kind: Function, | ||
929 | lookup: "foo", | ||
930 | detail: "fn foo(xs: Ve)", | ||
931 | trigger_call_info: true, | ||
932 | }, | ||
933 | ] | ||
934 | "### | ||
935 | ); | 960 | ); |
936 | assert_debug_snapshot!( | 961 | check_edit( |
937 | do_reference_completion( | 962 | "Vec", |
938 | r" | 963 | r#" |
939 | struct Vec<T> {} | 964 | struct Vec<T> {} |
940 | fn foo(xs: Ve<|><i128>) | 965 | fn foo(xs: Ve<|><i128>) |
941 | " | 966 | "#, |
942 | ), | 967 | r#" |
943 | @r###" | 968 | struct Vec<T> {} |
944 | [ | 969 | fn foo(xs: Vec<i128>) |
945 | CompletionItem { | 970 | "#, |
946 | label: "Vec", | ||
947 | source_range: 28..30, | ||
948 | delete: 28..30, | ||
949 | insert: "Vec", | ||
950 | kind: Struct, | ||
951 | }, | ||
952 | CompletionItem { | ||
953 | label: "foo(…)", | ||
954 | source_range: 28..30, | ||
955 | delete: 28..30, | ||
956 | insert: "foo(${1:xs})$0", | ||
957 | kind: Function, | ||
958 | lookup: "foo", | ||
959 | detail: "fn foo(xs: Ve<i128>)", | ||
960 | trigger_call_info: true, | ||
961 | }, | ||
962 | ] | ||
963 | "### | ||
964 | ); | 971 | ); |
965 | } | 972 | } |
966 | 973 | ||
967 | #[test] | 974 | #[test] |
968 | fn dont_insert_macro_call_parens_unncessary() { | 975 | fn dont_insert_macro_call_parens_unncessary() { |
969 | mark::check!(dont_insert_macro_call_parens_unncessary); | 976 | mark::check!(dont_insert_macro_call_parens_unncessary); |
970 | assert_debug_snapshot!( | 977 | check_edit( |
971 | do_reference_completion( | 978 | "frobnicate!", |
972 | r" | 979 | r#" |
973 | //- /main.rs | 980 | //- /main.rs |
974 | use foo::<|>; | 981 | use foo::<|>; |
975 | 982 | //- /foo/lib.rs | |
976 | //- /foo/lib.rs | 983 | #[macro_export] |
977 | #[macro_export] | 984 | macro_rules frobnicate { () => () } |
978 | macro_rules frobnicate { | 985 | "#, |
979 | () => () | 986 | r#" |
980 | } | 987 | use foo::frobnicate; |
981 | " | 988 | "#, |
982 | ), | ||
983 | @r###" | ||
984 | [ | ||
985 | CompletionItem { | ||
986 | label: "frobnicate!", | ||
987 | source_range: 9..9, | ||
988 | delete: 9..9, | ||
989 | insert: "frobnicate", | ||
990 | kind: Macro, | ||
991 | detail: "#[macro_export]\nmacro_rules! frobnicate", | ||
992 | }, | ||
993 | ] | ||
994 | "### | ||
995 | ); | ||
996 | |||
997 | assert_debug_snapshot!( | ||
998 | do_reference_completion( | ||
999 | r" | ||
1000 | //- /main.rs | ||
1001 | macro_rules frobnicate { | ||
1002 | () => () | ||
1003 | } | ||
1004 | fn main() { | ||
1005 | frob<|>!(); | ||
1006 | } | ||
1007 | " | ||
1008 | ), | ||
1009 | @r###" | ||
1010 | [ | ||
1011 | CompletionItem { | ||
1012 | label: "frobnicate!", | ||
1013 | source_range: 56..60, | ||
1014 | delete: 56..60, | ||
1015 | insert: "frobnicate", | ||
1016 | kind: Macro, | ||
1017 | detail: "macro_rules! frobnicate", | ||
1018 | }, | ||
1019 | CompletionItem { | ||
1020 | label: "main()", | ||
1021 | source_range: 56..60, | ||
1022 | delete: 56..60, | ||
1023 | insert: "main()$0", | ||
1024 | kind: Function, | ||
1025 | lookup: "main", | ||
1026 | detail: "fn main()", | ||
1027 | }, | ||
1028 | ] | ||
1029 | "### | ||
1030 | ); | 989 | ); |
1031 | } | ||
1032 | 990 | ||
1033 | #[test] | 991 | check_edit( |
1034 | fn test_struct_field_completion_in_func_call() { | 992 | "frobnicate!", |
1035 | mark::check!(test_struct_field_completion_in_func_call); | 993 | r#" |
1036 | assert_debug_snapshot!( | 994 | macro_rules frobnicate { () => () } |
1037 | do_reference_completion( | 995 | fn main() { frob<|>!(); } |
1038 | r" | 996 | "#, |
1039 | struct A { another_field: i64, the_field: u32, my_string: String } | 997 | r#" |
1040 | fn test(my_param: u32) -> u32 { my_param } | 998 | macro_rules frobnicate { () => () } |
1041 | fn foo(a: A) { | 999 | fn main() { frobnicate!(); } |
1042 | test(a.<|>) | 1000 | "#, |
1043 | } | ||
1044 | ", | ||
1045 | ), | ||
1046 | @r###" | ||
1047 | [ | ||
1048 | CompletionItem { | ||
1049 | label: "another_field", | ||
1050 | source_range: 136..136, | ||
1051 | delete: 136..136, | ||
1052 | insert: "another_field", | ||
1053 | kind: Field, | ||
1054 | detail: "i64", | ||
1055 | }, | ||
1056 | CompletionItem { | ||
1057 | label: "my_string", | ||
1058 | source_range: 136..136, | ||
1059 | delete: 136..136, | ||
1060 | insert: "my_string", | ||
1061 | kind: Field, | ||
1062 | detail: "{unknown}", | ||
1063 | }, | ||
1064 | CompletionItem { | ||
1065 | label: "the_field", | ||
1066 | source_range: 136..136, | ||
1067 | delete: 136..136, | ||
1068 | insert: "the_field", | ||
1069 | kind: Field, | ||
1070 | detail: "u32", | ||
1071 | score: TypeMatch, | ||
1072 | }, | ||
1073 | ] | ||
1074 | "### | ||
1075 | ); | 1001 | ); |
1076 | } | 1002 | } |
1077 | 1003 | ||
1078 | #[test] | 1004 | #[test] |
1079 | fn test_struct_field_completion_in_func_call_with_type_and_name() { | 1005 | fn active_param_score() { |
1080 | assert_debug_snapshot!( | 1006 | mark::check!(active_param_type_match); |
1081 | do_reference_completion( | 1007 | check_scores( |
1082 | r" | 1008 | r#" |
1083 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1009 | struct S { foo: i64, bar: u32, baz: u32 } |
1084 | fn test(the_field: u32) -> u32 { the_field } | 1010 | fn test(bar: u32) { } |
1085 | fn foo(a: A) { | 1011 | fn foo(s: S) { test(s.<|>) } |
1086 | test(a.<|>) | 1012 | "#, |
1087 | } | 1013 | expect![[r#" |
1088 | ", | 1014 | fd bar [type+name] |
1089 | ), | 1015 | fd baz [type] |
1090 | @r###" | 1016 | fd foo [] |
1091 | [ | 1017 | "#]], |
1092 | CompletionItem { | ||
1093 | label: "another_field", | ||
1094 | source_range: 143..143, | ||
1095 | delete: 143..143, | ||
1096 | insert: "another_field", | ||
1097 | kind: Field, | ||
1098 | detail: "i64", | ||
1099 | }, | ||
1100 | CompletionItem { | ||
1101 | label: "another_good_type", | ||
1102 | source_range: 143..143, | ||
1103 | delete: 143..143, | ||
1104 | insert: "another_good_type", | ||
1105 | kind: Field, | ||
1106 | detail: "u32", | ||
1107 | score: TypeMatch, | ||
1108 | }, | ||
1109 | CompletionItem { | ||
1110 | label: "the_field", | ||
1111 | source_range: 143..143, | ||
1112 | delete: 143..143, | ||
1113 | insert: "the_field", | ||
1114 | kind: Field, | ||
1115 | detail: "u32", | ||
1116 | score: TypeAndNameMatch, | ||
1117 | }, | ||
1118 | ] | ||
1119 | "### | ||
1120 | ); | 1018 | ); |
1121 | } | 1019 | } |
1122 | 1020 | ||
1123 | #[test] | 1021 | #[test] |
1124 | fn test_struct_field_completion_in_record_lit() { | 1022 | fn record_field_scores() { |
1125 | mark::check!(test_struct_field_completion_in_record_lit); | 1023 | mark::check!(record_field_type_match); |
1126 | assert_debug_snapshot!( | 1024 | check_scores( |
1127 | do_reference_completion( | 1025 | r#" |
1128 | r" | 1026 | struct A { foo: i64, bar: u32, baz: u32 } |
1129 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1027 | struct B { x: (), y: f32, bar: u32 } |
1130 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | 1028 | fn foo(a: A) { B { bar: a.<|> }; } |
1131 | fn foo(a: A) { | 1029 | "#, |
1132 | let b = B { | 1030 | expect![[r#" |
1133 | the_field: a.<|> | 1031 | fd bar [type+name] |
1134 | }; | 1032 | fd baz [type] |
1135 | } | 1033 | fd foo [] |
1136 | ", | 1034 | "#]], |
1137 | ), | 1035 | ) |
1138 | @r###" | ||
1139 | [ | ||
1140 | CompletionItem { | ||
1141 | label: "another_field", | ||
1142 | source_range: 189..189, | ||
1143 | delete: 189..189, | ||
1144 | insert: "another_field", | ||
1145 | kind: Field, | ||
1146 | detail: "i64", | ||
1147 | }, | ||
1148 | CompletionItem { | ||
1149 | label: "another_good_type", | ||
1150 | source_range: 189..189, | ||
1151 | delete: 189..189, | ||
1152 | insert: "another_good_type", | ||
1153 | kind: Field, | ||
1154 | detail: "u32", | ||
1155 | score: TypeMatch, | ||
1156 | }, | ||
1157 | CompletionItem { | ||
1158 | label: "the_field", | ||
1159 | source_range: 189..189, | ||
1160 | delete: 189..189, | ||
1161 | insert: "the_field", | ||
1162 | kind: Field, | ||
1163 | detail: "u32", | ||
1164 | score: TypeAndNameMatch, | ||
1165 | }, | ||
1166 | ] | ||
1167 | "### | ||
1168 | ); | ||
1169 | } | 1036 | } |
1170 | 1037 | ||
1171 | #[test] | 1038 | #[test] |
1172 | fn test_struct_field_completion_in_record_lit_and_fn_call() { | 1039 | fn record_field_and_call_scores() { |
1173 | assert_debug_snapshot!( | 1040 | check_scores( |
1174 | do_reference_completion( | 1041 | r#" |
1175 | r" | 1042 | struct A { foo: i64, bar: u32, baz: u32 } |
1176 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1043 | struct B { x: (), y: f32, bar: u32 } |
1177 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | 1044 | fn f(foo: i64) { } |
1178 | fn test(the_field: i64) -> i64 { the_field } | 1045 | fn foo(a: A) { B { bar: f(a.<|>) }; } |
1179 | fn foo(a: A) { | 1046 | "#, |
1180 | let b = B { | 1047 | expect![[r#" |
1181 | the_field: test(a.<|>) | 1048 | fd foo [type+name] |
1182 | }; | 1049 | fd bar [] |
1183 | } | 1050 | fd baz [] |
1184 | ", | 1051 | "#]], |
1185 | ), | ||
1186 | @r###" | ||
1187 | [ | ||
1188 | CompletionItem { | ||
1189 | label: "another_field", | ||
1190 | source_range: 239..239, | ||
1191 | delete: 239..239, | ||
1192 | insert: "another_field", | ||
1193 | kind: Field, | ||
1194 | detail: "i64", | ||
1195 | score: TypeMatch, | ||
1196 | }, | ||
1197 | CompletionItem { | ||
1198 | label: "another_good_type", | ||
1199 | source_range: 239..239, | ||
1200 | delete: 239..239, | ||
1201 | insert: "another_good_type", | ||
1202 | kind: Field, | ||
1203 | detail: "u32", | ||
1204 | }, | ||
1205 | CompletionItem { | ||
1206 | label: "the_field", | ||
1207 | source_range: 239..239, | ||
1208 | delete: 239..239, | ||
1209 | insert: "the_field", | ||
1210 | kind: Field, | ||
1211 | detail: "u32", | ||
1212 | }, | ||
1213 | ] | ||
1214 | "### | ||
1215 | ); | 1052 | ); |
1216 | } | 1053 | check_scores( |
1217 | 1054 | r#" | |
1218 | #[test] | 1055 | struct A { foo: i64, bar: u32, baz: u32 } |
1219 | fn test_struct_field_completion_in_fn_call_and_record_lit() { | 1056 | struct B { x: (), y: f32, bar: u32 } |
1220 | assert_debug_snapshot!( | 1057 | fn f(foo: i64) { } |
1221 | do_reference_completion( | 1058 | fn foo(a: A) { f(B { bar: a.<|> }); } |
1222 | r" | 1059 | "#, |
1223 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1060 | expect![[r#" |
1224 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | 1061 | fd bar [type+name] |
1225 | fn test(the_field: i64) -> i64 { the_field } | 1062 | fd baz [type] |
1226 | fn foo(a: A) { | 1063 | fd foo [] |
1227 | test(B { | 1064 | "#]], |
1228 | the_field: a.<|> | ||
1229 | }); | ||
1230 | } | ||
1231 | ", | ||
1232 | ), | ||
1233 | @r###" | ||
1234 | [ | ||
1235 | CompletionItem { | ||
1236 | label: "another_field", | ||
1237 | source_range: 231..231, | ||
1238 | delete: 231..231, | ||
1239 | insert: "another_field", | ||
1240 | kind: Field, | ||
1241 | detail: "i64", | ||
1242 | }, | ||
1243 | CompletionItem { | ||
1244 | label: "another_good_type", | ||
1245 | source_range: 231..231, | ||
1246 | delete: 231..231, | ||
1247 | insert: "another_good_type", | ||
1248 | kind: Field, | ||
1249 | detail: "u32", | ||
1250 | score: TypeMatch, | ||
1251 | }, | ||
1252 | CompletionItem { | ||
1253 | label: "the_field", | ||
1254 | source_range: 231..231, | ||
1255 | delete: 231..231, | ||
1256 | insert: "the_field", | ||
1257 | kind: Field, | ||
1258 | detail: "u32", | ||
1259 | score: TypeAndNameMatch, | ||
1260 | }, | ||
1261 | ] | ||
1262 | "### | ||
1263 | ); | 1065 | ); |
1264 | } | 1066 | } |
1265 | 1067 | ||
1266 | #[test] | 1068 | #[test] |
1267 | fn prioritize_exact_ref_match() { | 1069 | fn prioritize_exact_ref_match() { |
1268 | assert_debug_snapshot!( | 1070 | check_scores( |
1269 | do_reference_completion( | 1071 | r#" |
1270 | r" | 1072 | struct WorldSnapshot { _f: () }; |
1271 | struct WorldSnapshot { _f: () }; | 1073 | fn go(world: &WorldSnapshot) { go(w<|>) } |
1272 | fn go(world: &WorldSnapshot) { | 1074 | "#, |
1273 | go(w<|>) | 1075 | expect![[r#" |
1274 | } | 1076 | bn world [type+name] |
1275 | ", | 1077 | st WorldSnapshot [] |
1276 | ), | 1078 | fn go(…) [] |
1277 | @r###" | 1079 | "#]], |
1278 | [ | ||
1279 | CompletionItem { | ||
1280 | label: "WorldSnapshot", | ||
1281 | source_range: 71..72, | ||
1282 | delete: 71..72, | ||
1283 | insert: "WorldSnapshot", | ||
1284 | kind: Struct, | ||
1285 | }, | ||
1286 | CompletionItem { | ||
1287 | label: "go(…)", | ||
1288 | source_range: 71..72, | ||
1289 | delete: 71..72, | ||
1290 | insert: "go(${1:world})$0", | ||
1291 | kind: Function, | ||
1292 | lookup: "go", | ||
1293 | detail: "fn go(world: &WorldSnapshot)", | ||
1294 | trigger_call_info: true, | ||
1295 | }, | ||
1296 | CompletionItem { | ||
1297 | label: "world", | ||
1298 | source_range: 71..72, | ||
1299 | delete: 71..72, | ||
1300 | insert: "world", | ||
1301 | kind: Binding, | ||
1302 | detail: "&WorldSnapshot", | ||
1303 | score: TypeAndNameMatch, | ||
1304 | }, | ||
1305 | ] | ||
1306 | "### | ||
1307 | ); | 1080 | ); |
1308 | } | 1081 | } |
1309 | } | 1082 | } |
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs index 145d36c98..cbae1da85 100644 --- a/crates/ra_ide/src/completion/test_utils.rs +++ b/crates/ra_ide/src/completion/test_utils.rs | |||
@@ -13,15 +13,15 @@ use crate::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | 15 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { |
16 | do_completion_with_options(code, kind, &CompletionConfig::default()) | 16 | do_completion_with_config(code, kind, &CompletionConfig::default()) |
17 | } | 17 | } |
18 | 18 | ||
19 | pub(crate) fn do_completion_with_options( | 19 | pub(crate) fn do_completion_with_config( |
20 | code: &str, | 20 | code: &str, |
21 | kind: CompletionKind, | 21 | kind: CompletionKind, |
22 | options: &CompletionConfig, | 22 | config: &CompletionConfig, |
23 | ) -> Vec<CompletionItem> { | 23 | ) -> Vec<CompletionItem> { |
24 | let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, options) | 24 | let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, config) |
25 | .into_iter() | 25 | .into_iter() |
26 | .filter(|c| c.completion_kind == kind) | 26 | .filter(|c| c.completion_kind == kind) |
27 | .collect(); | 27 | .collect(); |
@@ -30,15 +30,15 @@ pub(crate) fn do_completion_with_options( | |||
30 | } | 30 | } |
31 | 31 | ||
32 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { | 32 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { |
33 | completion_list_with_options(code, kind, &CompletionConfig::default()) | 33 | completion_list_with_config(code, kind, &CompletionConfig::default()) |
34 | } | 34 | } |
35 | 35 | ||
36 | pub(crate) fn completion_list_with_options( | 36 | pub(crate) fn completion_list_with_config( |
37 | code: &str, | 37 | code: &str, |
38 | kind: CompletionKind, | 38 | kind: CompletionKind, |
39 | options: &CompletionConfig, | 39 | config: &CompletionConfig, |
40 | ) -> String { | 40 | ) -> String { |
41 | let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, options) | 41 | let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, config) |
42 | .into_iter() | 42 | .into_iter() |
43 | .filter(|c| c.completion_kind == kind) | 43 | .filter(|c| c.completion_kind == kind) |
44 | .collect(); | 44 | .collect(); |
@@ -92,7 +92,10 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) - | |||
92 | .unwrap(); | 92 | .unwrap(); |
93 | } | 93 | } |
94 | 94 | ||
95 | fn get_all_completion_items(code: &str, options: &CompletionConfig) -> Vec<CompletionItem> { | 95 | pub(crate) fn get_all_completion_items( |
96 | code: &str, | ||
97 | options: &CompletionConfig, | ||
98 | ) -> Vec<CompletionItem> { | ||
96 | let (analysis, position) = analysis_and_position(code); | 99 | let (analysis, position) = analysis_and_position(code); |
97 | analysis.completions(options, position).unwrap().unwrap().into() | 100 | analysis.completions(options, position).unwrap().unwrap().into() |
98 | } | 101 | } |