aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs988
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs35
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs39
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs2
-rw-r--r--crates/ra_ide/src/completion/presentation.rs911
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs21
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
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, Type};
4
5use crate::{
6 completion::{
7 completion_context::CompletionContext,
8 completion_item::{CompletionKind, Completions},
9 },
10 CompletionItem,
11};
12use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark;
13 6
14/// Complete dot accesses, i.e. fields or methods (and .await syntax). 7use crate::completion::{completion_context::CompletionContext, completion_item::Completions};
8
9/// Complete dot accesses, i.e. fields or methods.
15pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(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
40fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 29fn 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)]
74mod tests { 63mod 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" 78struct S { foo: u32 }
87 struct A { the_field: u32 } 79impl S {
88 fn foo(a: A) { 80 fn bar(&self) {}
89 a.<|> 81}
90 } 82fn 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" 95struct S { the_field: (u32,) }
113 struct A { 96impl 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" 111struct A { the_field: (u32, i32) }
156 struct A { the_field: (u32, i32) } 112impl 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 } 128struct A { the_field: u32 }
194 fn foo(a: A) { 129fn 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" 139mod 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] 147fn 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!( 158struct A {}
293 do_ref_completion( 159mod 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) { 165fn 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" 177union U { field: u8, other: u16 }
325 struct A<T> {} 178fn 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" 191struct A<T> {}
358 struct A {} 192impl A<u32> {
359 mod m { 193 fn the_method(&self) {}
360 impl super::A { 194}
361 fn private_method(&self) {} 195impl A<i32> {
362 pub(super) fn the_method(&self) {} 196 fn the_other_method(&self) {}
363 } 197}
364 } 198fn 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" 210struct A {}
391 struct A {} 211trait Trait { fn the_method(&self); }
392 trait Trait { fn the_method(&self); } 212impl Trait for A {}
393 impl Trait for A {} 213fn 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" 225struct A {}
420 struct A {} 226trait Trait { fn the_method(&self); }
421 trait Trait { fn the_method(&self); } 227impl<T> Trait for T {}
422 impl<T> Trait for T {} 228fn 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 {} 240struct A {}
482 impl A { 241mod m {
483 fn the_method() {} 242 pub trait Trait { fn the_method(&self); }
484 } 243}
485 fn foo(a: A) { 244use m::Trait;
486 a.<|> 245impl Trait for A {}
487 } 246fn 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" 258struct A {}
499 struct A {} 259impl A {
500 impl A { 260 fn the_method() {}
501 #[inline] 261}
502 fn the_method(&self) { 262fn 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" 274fn 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" 290pub struct S;
567 pub struct S; 291impl S { pub fn blah(&self) {} }
568 impl S {
569 pub fn blah(&self) {}
570 }
571 292
572 struct T(S); 293struct T(S);
573 294
574 impl T { 295impl 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###" 312struct A { the_field: u32 }
629 //- /main.rs 313const 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" 327macro_rules! m { ($e:expr) => { $e } }
701 macro_rules! m { ($e:expr) => { $e } } 328struct A { the_field: u32 }
702 struct A { the_field: u32 } 329fn 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" 344macro_rules! m { ($e:expr) => { $e } }
756 macro_rules! m { ($e:expr) => { $e } } 345struct A { the_field: u32 }
757 struct A { the_field: u32 } 346fn 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" 360macro_rules! m { ($e:expr) => { $e } }
783 macro_rules! m { ($e:expr) => { $e } } 361struct A { the_field: u32 }
784 struct A { the_field: u32 } 362fn 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" 376macro_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 } 387struct A { the_field: u32 }
821 struct A { the_field: u32 } 388fn 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" 402struct HashSet<T> {}
847 struct HashSet<T> {} 403impl<T> HashSet<T> {
848 impl<T> HashSet<T> { 404 pub fn the_method(&self) {}
849 pub fn the_method(&self) {} 405}
850 } 406fn 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
40pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 53pub(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
512use std::future::*;
513struct A {}
514impl Future for A {}
515fn foo(a: A) { a.<|> }
516
517//- /std/lib.rs
518pub 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)]
99pub enum CompletionScore { 99pub 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
3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; 4use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
4use ra_syntax::ast::NameOwner; 5use 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)]
463mod tests { 464mod 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 { 512enum Foo { Foo { x: i32, y: i32 } }
482 Foo {x: i32, y: i32}
483 }
484 513
485 fn main() { Foo::Fo<|> } 514fn 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 { 535enum Foo { Foo (i32, i32) }
509 Foo (i32, i32)
510 }
511 536
512 fn main() { Foo::Fo<|> } 537fn 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 { 560enum Foo { Foo }
538 Foo
539 }
540 561
541 fn main() { Foo::Fo<|> } 562fn 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] 584fn something_deprecated() {}
565 fn something_deprecated() {} 585#[deprecated(since = "1.0.0")]
566 586fn something_else_deprecated() {}
567 #[deprecated(since = "1.0.0")] 587
568 fn something_else_deprecated() {} 588fn 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#"
627struct A { #[deprecated] the_field: u32 }
628fn 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#"
610struct A { 650struct S {
611 #[deprecated] 651 /// Field docs
612 the_field: u32, 652 foo:
613} 653}
614fn foo() { 654impl 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#"
692struct S;
693impl S {
694 #[inline]
695 fn the_method(&self) { }
616} 696}
697fn 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> {} 931struct Vec<T> {}
851 fn foo(xs: Ve<|>) 932fn foo(xs: Ve<|>)
852 " 933"#,
853 ), 934 r#"
854 @r###" 935struct Vec<T> {}
855 [ 936fn 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,); 942type Vec<T> = (T,);
881 fn foo(xs: Ve<|>) 943fn foo(xs: Ve<|>)
882 " 944"#,
883 ), 945 r#"
884 @r###" 946type Vec<T> = (T,);
885 [ 947fn 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> {} 953struct Vec<T = i128> {}
911 fn foo(xs: Ve<|>) 954fn foo(xs: Ve<|>)
912 " 955"#,
913 ), 956 r#"
914 @r###" 957struct Vec<T = i128> {}
915 [ 958fn 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> {} 964struct Vec<T> {}
940 fn foo(xs: Ve<|><i128>) 965fn foo(xs: Ve<|><i128>)
941 " 966"#,
942 ), 967 r#"
943 @r###" 968struct Vec<T> {}
944 [ 969fn 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::<|>; 981use foo::<|>;
975 982//- /foo/lib.rs
976 //- /foo/lib.rs 983#[macro_export]
977 #[macro_export] 984macro_rules frobnicate { () => () }
978 macro_rules frobnicate { 985"#,
979 () => () 986 r#"
980 } 987use 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!( 994macro_rules frobnicate { () => () }
1037 do_reference_completion( 995fn 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 } 998macro_rules frobnicate { () => () }
1041 fn foo(a: A) { 999fn 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 } 1009struct S { foo: i64, bar: u32, baz: u32 }
1084 fn test(the_field: u32) -> u32 { the_field } 1010fn test(bar: u32) { }
1085 fn foo(a: A) { 1011fn 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" 1026struct A { foo: i64, bar: u32, baz: u32 }
1129 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1027struct B { x: (), y: f32, bar: u32 }
1130 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1028fn 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" 1042struct A { foo: i64, bar: u32, baz: u32 }
1176 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1043struct B { x: (), y: f32, bar: u32 }
1177 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1044fn f(foo: i64) { }
1178 fn test(the_field: i64) -> i64 { the_field } 1045fn 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] 1055struct A { foo: i64, bar: u32, baz: u32 }
1219 fn test_struct_field_completion_in_fn_call_and_record_lit() { 1056struct B { x: (), y: f32, bar: u32 }
1220 assert_debug_snapshot!( 1057fn f(foo: i64) { }
1221 do_reference_completion( 1058fn 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" 1072struct WorldSnapshot { _f: () };
1271 struct WorldSnapshot { _f: () }; 1073fn 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
15pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 15pub(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
19pub(crate) fn do_completion_with_options( 19pub(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
32pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { 32pub(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
36pub(crate) fn completion_list_with_options( 36pub(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
95fn get_all_completion_items(code: &str, options: &CompletionConfig) -> Vec<CompletionItem> { 95pub(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}