aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs973
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs445
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs546
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs20
-rw-r--r--crates/ra_ide/src/completion/presentation.rs680
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs36
6 files changed, 854 insertions, 1846 deletions
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index 6beeca457..9db317509 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -46,7 +46,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
46 _ => {} 46 _ => {}
47 } 47 }
48 48
49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { 49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
50 acc.add(item); 50 acc.add(item);
51 } 51 }
52 } 52 }
@@ -56,159 +56,72 @@ struct AttrCompletion {
56 label: &'static str, 56 label: &'static str,
57 lookup: Option<&'static str>, 57 lookup: Option<&'static str>,
58 snippet: Option<&'static str>, 58 snippet: Option<&'static str>,
59 should_be_inner: bool, 59 prefer_inner: bool,
60}
61
62impl AttrCompletion {
63 const fn prefer_inner(self) -> AttrCompletion {
64 AttrCompletion { prefer_inner: true, ..self }
65 }
66}
67
68const fn attr(
69 label: &'static str,
70 lookup: Option<&'static str>,
71 snippet: Option<&'static str>,
72) -> AttrCompletion {
73 AttrCompletion { label, lookup, snippet, prefer_inner: false }
60} 74}
61 75
62const ATTRIBUTES: &[AttrCompletion] = &[ 76const ATTRIBUTES: &[AttrCompletion] = &[
63 AttrCompletion { 77 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
64 label: "allow(…)", 78 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
65 snippet: Some("allow(${0:lint})"), 79 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
66 should_be_inner: false, 80 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
67 lookup: Some("allow"), 81 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
68 }, 82 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
69 AttrCompletion { 83 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
70 label: "cfg_attr(…)", 84 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
71 snippet: Some("cfg_attr(${1:predicate}, ${0:attr})"), 85 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
72 should_be_inner: false,
73 lookup: Some("cfg_attr"),
74 },
75 AttrCompletion {
76 label: "cfg(…)",
77 snippet: Some("cfg(${0:predicate})"),
78 should_be_inner: false,
79 lookup: Some("cfg"),
80 },
81 AttrCompletion {
82 label: "deny(…)",
83 snippet: Some("deny(${0:lint})"),
84 should_be_inner: false,
85 lookup: Some("deny"),
86 },
87 AttrCompletion {
88 label: r#"deprecated = "…""#,
89 snippet: Some(r#"deprecated = "${0:reason}""#),
90 should_be_inner: false,
91 lookup: Some("deprecated"),
92 },
93 AttrCompletion {
94 label: "derive(…)",
95 snippet: Some(r#"derive(${0:Debug})"#),
96 should_be_inner: false,
97 lookup: Some("derive"),
98 },
99 AttrCompletion {
100 label: r#"doc = "…""#,
101 snippet: Some(r#"doc = "${0:docs}""#),
102 should_be_inner: false,
103 lookup: Some("doc"),
104 },
105 AttrCompletion {
106 label: "feature(…)",
107 snippet: Some("feature(${0:flag})"),
108 should_be_inner: true,
109 lookup: Some("feature"),
110 },
111 AttrCompletion {
112 label: "forbid(…)",
113 snippet: Some("forbid(${0:lint})"),
114 should_be_inner: false,
115 lookup: Some("forbid"),
116 },
117 // FIXME: resolve through macro resolution? 86 // FIXME: resolve through macro resolution?
118 AttrCompletion { 87 attr("global_allocator", None, None).prefer_inner(),
119 label: "global_allocator", 88 attr("ignore(…)", Some("ignore"), Some("ignore(${0:lint})")),
120 snippet: None, 89 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
121 should_be_inner: true, 90 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
122 lookup: None, 91 attr("link", None, None),
123 }, 92 attr("macro_export", None, None),
124 AttrCompletion { 93 attr("macro_use", None, None),
125 label: "ignore(…)", 94 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
126 snippet: Some("ignore(${0:lint})"), 95 attr("no_mangle", None, None),
127 should_be_inner: false, 96 attr("no_std", None, None).prefer_inner(),
128 lookup: Some("ignore"), 97 attr("non_exhaustive", None, None),
129 }, 98 attr("panic_handler", None, None).prefer_inner(),
130 AttrCompletion { 99 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")),
131 label: "inline(…)", 100 attr("proc_macro", None, None),
132 snippet: Some("inline(${0:lint})"), 101 attr("proc_macro_attribute", None, None),
133 should_be_inner: false, 102 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
134 lookup: Some("inline"), 103 attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}"))
135 }, 104 .prefer_inner(),
136 AttrCompletion { 105 attr("repr(…)", Some("repr"), Some("repr(${0:C})")),
137 label: r#"link_name = "…""#, 106 attr(
138 snippet: Some(r#"link_name = "${0:symbol_name}""#), 107 "should_panic(…)",
139 should_be_inner: false, 108 Some("should_panic"),
140 lookup: Some("link_name"), 109 Some(r#"should_panic(expected = "${0:reason}")"#),
141 }, 110 ),
142 AttrCompletion { label: "link", snippet: None, should_be_inner: false, lookup: None }, 111 attr(
143 AttrCompletion { label: "macro_export", snippet: None, should_be_inner: false, lookup: None }, 112 r#"target_feature = "…""#,
144 AttrCompletion { label: "macro_use", snippet: None, should_be_inner: false, lookup: None }, 113 Some("target_feature"),
145 AttrCompletion { 114 Some("target_feature = \"${0:feature}\""),
146 label: r#"must_use = "…""#, 115 ),
147 snippet: Some(r#"must_use = "${0:reason}""#), 116 attr("test", None, None),
148 should_be_inner: false, 117 attr("used", None, None),
149 lookup: Some("must_use"), 118 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
150 }, 119 attr(
151 AttrCompletion { label: "no_mangle", snippet: None, should_be_inner: false, lookup: None }, 120 r#"windows_subsystem = "…""#,
152 AttrCompletion { label: "no_std", snippet: None, should_be_inner: true, lookup: None }, 121 Some("windows_subsystem"),
153 AttrCompletion { label: "non_exhaustive", snippet: None, should_be_inner: false, lookup: None }, 122 Some(r#"windows_subsystem = "${0:subsystem}""#),
154 AttrCompletion { label: "panic_handler", snippet: None, should_be_inner: true, lookup: None }, 123 )
155 AttrCompletion { 124 .prefer_inner(),
156 label: "path = \"…\"",
157 snippet: Some("path =\"${0:path}\""),
158 should_be_inner: false,
159 lookup: Some("path"),
160 },
161 AttrCompletion { label: "proc_macro", snippet: None, should_be_inner: false, lookup: None },
162 AttrCompletion {
163 label: "proc_macro_attribute",
164 snippet: None,
165 should_be_inner: false,
166 lookup: None,
167 },
168 AttrCompletion {
169 label: "proc_macro_derive(…)",
170 snippet: Some("proc_macro_derive(${0:Trait})"),
171 should_be_inner: false,
172 lookup: Some("proc_macro_derive"),
173 },
174 AttrCompletion {
175 label: "recursion_limit = …",
176 snippet: Some("recursion_limit = ${0:128}"),
177 should_be_inner: true,
178 lookup: Some("recursion_limit"),
179 },
180 AttrCompletion {
181 label: "repr(…)",
182 snippet: Some("repr(${0:C})"),
183 should_be_inner: false,
184 lookup: Some("repr"),
185 },
186 AttrCompletion {
187 label: "should_panic(…)",
188 snippet: Some(r#"should_panic(expected = "${0:reason}")"#),
189 should_be_inner: false,
190 lookup: Some("should_panic"),
191 },
192 AttrCompletion {
193 label: r#"target_feature = "…""#,
194 snippet: Some("target_feature = \"${0:feature}\""),
195 should_be_inner: false,
196 lookup: Some("target_feature"),
197 },
198 AttrCompletion { label: "test", snippet: None, should_be_inner: false, lookup: None },
199 AttrCompletion { label: "used", snippet: None, should_be_inner: false, lookup: None },
200 AttrCompletion {
201 label: "warn(…)",
202 snippet: Some("warn(${0:lint})"),
203 should_be_inner: false,
204 lookup: Some("warn"),
205 },
206 AttrCompletion {
207 label: r#"windows_subsystem = "…""#,
208 snippet: Some(r#"windows_subsystem = "${0:subsystem}""#),
209 should_be_inner: true,
210 lookup: Some("windows_subsystem"),
211 },
212]; 125];
213 126
214fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { 127fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
@@ -313,677 +226,147 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
313 226
314#[cfg(test)] 227#[cfg(test)]
315mod tests { 228mod tests {
316 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 229 use expect::{expect, Expect};
317 use insta::assert_debug_snapshot;
318 230
319 fn do_attr_completion(code: &str) -> Vec<CompletionItem> { 231 use crate::completion::{test_utils::completion_list, CompletionKind};
320 do_completion(code, CompletionKind::Attribute) 232
233 fn check(ra_fixture: &str, expect: Expect) {
234 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
235 expect.assert_eq(&actual);
321 } 236 }
322 237
323 #[test] 238 #[test]
324 fn empty_derive_completion() { 239 fn empty_derive_completion() {
325 assert_debug_snapshot!( 240 check(
326 do_attr_completion( 241 r#"
327 r" 242#[derive(<|>)]
328 #[derive(<|>)] 243struct Test {}
329 struct Test {} 244 "#,
330 ", 245 expect![[r#"
331 ), 246 at Clone
332 @r###" 247 at Copy, Clone
333 [ 248 at Debug
334 CompletionItem { 249 at Default
335 label: "Clone", 250 at Eq, PartialEq
336 source_range: 9..9, 251 at Hash
337 delete: 9..9, 252 at Ord, PartialOrd, Eq, PartialEq
338 insert: "Clone", 253 at PartialEq
339 kind: Attribute, 254 at PartialOrd, PartialEq
340 }, 255 "#]],
341 CompletionItem {
342 label: "Copy, Clone",
343 source_range: 9..9,
344 delete: 9..9,
345 insert: "Copy, Clone",
346 kind: Attribute,
347 },
348 CompletionItem {
349 label: "Debug",
350 source_range: 9..9,
351 delete: 9..9,
352 insert: "Debug",
353 kind: Attribute,
354 },
355 CompletionItem {
356 label: "Default",
357 source_range: 9..9,
358 delete: 9..9,
359 insert: "Default",
360 kind: Attribute,
361 },
362 CompletionItem {
363 label: "Eq, PartialEq",
364 source_range: 9..9,
365 delete: 9..9,
366 insert: "Eq, PartialEq",
367 kind: Attribute,
368 },
369 CompletionItem {
370 label: "Hash",
371 source_range: 9..9,
372 delete: 9..9,
373 insert: "Hash",
374 kind: Attribute,
375 },
376 CompletionItem {
377 label: "Ord, PartialOrd, Eq, PartialEq",
378 source_range: 9..9,
379 delete: 9..9,
380 insert: "Ord, PartialOrd, Eq, PartialEq",
381 kind: Attribute,
382 },
383 CompletionItem {
384 label: "PartialEq",
385 source_range: 9..9,
386 delete: 9..9,
387 insert: "PartialEq",
388 kind: Attribute,
389 },
390 CompletionItem {
391 label: "PartialOrd, PartialEq",
392 source_range: 9..9,
393 delete: 9..9,
394 insert: "PartialOrd, PartialEq",
395 kind: Attribute,
396 },
397 ]
398 "###
399 ); 256 );
400 } 257 }
401 258
402 #[test] 259 #[test]
403 fn no_completion_for_incorrect_derive() { 260 fn no_completion_for_incorrect_derive() {
404 assert_debug_snapshot!( 261 check(
405 do_attr_completion( 262 r#"
406 r" 263#[derive{<|>)]
407 #[derive{<|>)] 264struct Test {}
408 struct Test {} 265"#,
409 ", 266 expect![[r#""#]],
410 ), 267 )
411 @"[]"
412 );
413 } 268 }
414 269
415 #[test] 270 #[test]
416 fn derive_with_input_completion() { 271 fn derive_with_input_completion() {
417 assert_debug_snapshot!( 272 check(
418 do_attr_completion( 273 r#"
419 r" 274#[derive(serde::Serialize, PartialEq, <|>)]
420 #[derive(serde::Serialize, PartialEq, <|>)] 275struct Test {}
421 struct Test {} 276"#,
422 ", 277 expect![[r#"
423 ), 278 at Clone
424 @r###" 279 at Copy, Clone
425 [ 280 at Debug
426 CompletionItem { 281 at Default
427 label: "Clone", 282 at Eq
428 source_range: 38..38, 283 at Hash
429 delete: 38..38, 284 at Ord, PartialOrd, Eq
430 insert: "Clone", 285 at PartialOrd
431 kind: Attribute, 286 "#]],
432 }, 287 )
433 CompletionItem {
434 label: "Copy, Clone",
435 source_range: 38..38,
436 delete: 38..38,
437 insert: "Copy, Clone",
438 kind: Attribute,
439 },
440 CompletionItem {
441 label: "Debug",
442 source_range: 38..38,
443 delete: 38..38,
444 insert: "Debug",
445 kind: Attribute,
446 },
447 CompletionItem {
448 label: "Default",
449 source_range: 38..38,
450 delete: 38..38,
451 insert: "Default",
452 kind: Attribute,
453 },
454 CompletionItem {
455 label: "Eq",
456 source_range: 38..38,
457 delete: 38..38,
458 insert: "Eq",
459 kind: Attribute,
460 },
461 CompletionItem {
462 label: "Hash",
463 source_range: 38..38,
464 delete: 38..38,
465 insert: "Hash",
466 kind: Attribute,
467 },
468 CompletionItem {
469 label: "Ord, PartialOrd, Eq",
470 source_range: 38..38,
471 delete: 38..38,
472 insert: "Ord, PartialOrd, Eq",
473 kind: Attribute,
474 },
475 CompletionItem {
476 label: "PartialOrd",
477 source_range: 38..38,
478 delete: 38..38,
479 insert: "PartialOrd",
480 kind: Attribute,
481 },
482 ]
483 "###
484 );
485 } 288 }
486 289
487 #[test] 290 #[test]
488 fn test_attribute_completion() { 291 fn test_attribute_completion() {
489 assert_debug_snapshot!( 292 check(
490 do_attr_completion( 293 r#"#[<|>]"#,
491 r" 294 expect![[r#"
492 #[<|>] 295 at allow(…)
493 ", 296 at cfg(…)
494 ), 297 at cfg_attr(…)
495 @r###" 298 at deny(…)
496 [ 299 at deprecated = "…"
497 CompletionItem { 300 at derive(…)
498 label: "allow(…)", 301 at doc = "…"
499 source_range: 2..2, 302 at forbid(…)
500 delete: 2..2, 303 at ignore(…)
501 insert: "allow(${0:lint})", 304 at inline(…)
502 kind: Attribute, 305 at link
503 lookup: "allow", 306 at link_name = "…"
504 }, 307 at macro_export
505 CompletionItem { 308 at macro_use
506 label: "cfg(…)", 309 at must_use = "…"
507 source_range: 2..2, 310 at no_mangle
508 delete: 2..2, 311 at non_exhaustive
509 insert: "cfg(${0:predicate})", 312 at path = "…"
510 kind: Attribute, 313 at proc_macro
511 lookup: "cfg", 314 at proc_macro_attribute
512 }, 315 at proc_macro_derive(…)
513 CompletionItem { 316 at repr(…)
514 label: "cfg_attr(…)", 317 at should_panic(…)
515 source_range: 2..2, 318 at target_feature = "…"
516 delete: 2..2, 319 at test
517 insert: "cfg_attr(${1:predicate}, ${0:attr})", 320 at used
518 kind: Attribute, 321 at warn(…)
519 lookup: "cfg_attr", 322 "#]],
520 }, 323 )
521 CompletionItem {
522 label: "deny(…)",
523 source_range: 2..2,
524 delete: 2..2,
525 insert: "deny(${0:lint})",
526 kind: Attribute,
527 lookup: "deny",
528 },
529 CompletionItem {
530 label: "deprecated = \"…\"",
531 source_range: 2..2,
532 delete: 2..2,
533 insert: "deprecated = \"${0:reason}\"",
534 kind: Attribute,
535 lookup: "deprecated",
536 },
537 CompletionItem {
538 label: "derive(…)",
539 source_range: 2..2,
540 delete: 2..2,
541 insert: "derive(${0:Debug})",
542 kind: Attribute,
543 lookup: "derive",
544 },
545 CompletionItem {
546 label: "doc = \"…\"",
547 source_range: 2..2,
548 delete: 2..2,
549 insert: "doc = \"${0:docs}\"",
550 kind: Attribute,
551 lookup: "doc",
552 },
553 CompletionItem {
554 label: "forbid(…)",
555 source_range: 2..2,
556 delete: 2..2,
557 insert: "forbid(${0:lint})",
558 kind: Attribute,
559 lookup: "forbid",
560 },
561 CompletionItem {
562 label: "ignore(…)",
563 source_range: 2..2,
564 delete: 2..2,
565 insert: "ignore(${0:lint})",
566 kind: Attribute,
567 lookup: "ignore",
568 },
569 CompletionItem {
570 label: "inline(…)",
571 source_range: 2..2,
572 delete: 2..2,
573 insert: "inline(${0:lint})",
574 kind: Attribute,
575 lookup: "inline",
576 },
577 CompletionItem {
578 label: "link",
579 source_range: 2..2,
580 delete: 2..2,
581 insert: "link",
582 kind: Attribute,
583 },
584 CompletionItem {
585 label: "link_name = \"…\"",
586 source_range: 2..2,
587 delete: 2..2,
588 insert: "link_name = \"${0:symbol_name}\"",
589 kind: Attribute,
590 lookup: "link_name",
591 },
592 CompletionItem {
593 label: "macro_export",
594 source_range: 2..2,
595 delete: 2..2,
596 insert: "macro_export",
597 kind: Attribute,
598 },
599 CompletionItem {
600 label: "macro_use",
601 source_range: 2..2,
602 delete: 2..2,
603 insert: "macro_use",
604 kind: Attribute,
605 },
606 CompletionItem {
607 label: "must_use = \"…\"",
608 source_range: 2..2,
609 delete: 2..2,
610 insert: "must_use = \"${0:reason}\"",
611 kind: Attribute,
612 lookup: "must_use",
613 },
614 CompletionItem {
615 label: "no_mangle",
616 source_range: 2..2,
617 delete: 2..2,
618 insert: "no_mangle",
619 kind: Attribute,
620 },
621 CompletionItem {
622 label: "non_exhaustive",
623 source_range: 2..2,
624 delete: 2..2,
625 insert: "non_exhaustive",
626 kind: Attribute,
627 },
628 CompletionItem {
629 label: "path = \"…\"",
630 source_range: 2..2,
631 delete: 2..2,
632 insert: "path =\"${0:path}\"",
633 kind: Attribute,
634 lookup: "path",
635 },
636 CompletionItem {
637 label: "proc_macro",
638 source_range: 2..2,
639 delete: 2..2,
640 insert: "proc_macro",
641 kind: Attribute,
642 },
643 CompletionItem {
644 label: "proc_macro_attribute",
645 source_range: 2..2,
646 delete: 2..2,
647 insert: "proc_macro_attribute",
648 kind: Attribute,
649 },
650 CompletionItem {
651 label: "proc_macro_derive(…)",
652 source_range: 2..2,
653 delete: 2..2,
654 insert: "proc_macro_derive(${0:Trait})",
655 kind: Attribute,
656 lookup: "proc_macro_derive",
657 },
658 CompletionItem {
659 label: "repr(…)",
660 source_range: 2..2,
661 delete: 2..2,
662 insert: "repr(${0:C})",
663 kind: Attribute,
664 lookup: "repr",
665 },
666 CompletionItem {
667 label: "should_panic(…)",
668 source_range: 2..2,
669 delete: 2..2,
670 insert: "should_panic(expected = \"${0:reason}\")",
671 kind: Attribute,
672 lookup: "should_panic",
673 },
674 CompletionItem {
675 label: "target_feature = \"…\"",
676 source_range: 2..2,
677 delete: 2..2,
678 insert: "target_feature = \"${0:feature}\"",
679 kind: Attribute,
680 lookup: "target_feature",
681 },
682 CompletionItem {
683 label: "test",
684 source_range: 2..2,
685 delete: 2..2,
686 insert: "test",
687 kind: Attribute,
688 },
689 CompletionItem {
690 label: "used",
691 source_range: 2..2,
692 delete: 2..2,
693 insert: "used",
694 kind: Attribute,
695 },
696 CompletionItem {
697 label: "warn(…)",
698 source_range: 2..2,
699 delete: 2..2,
700 insert: "warn(${0:lint})",
701 kind: Attribute,
702 lookup: "warn",
703 },
704 ]
705 "###
706 );
707 } 324 }
708 325
709 #[test] 326 #[test]
710 fn test_attribute_completion_inside_nested_attr() { 327 fn test_attribute_completion_inside_nested_attr() {
711 assert_debug_snapshot!( 328 check(r#"#[allow(<|>)]"#, expect![[]])
712 do_attr_completion(
713 r"
714 #[allow(<|>)]
715 ",
716 ),
717 @r###"
718 []
719 "###
720 );
721 } 329 }
722 330
723 #[test] 331 #[test]
724 fn test_inner_attribute_completion() { 332 fn test_inner_attribute_completion() {
725 assert_debug_snapshot!( 333 check(
726 do_attr_completion( 334 r"#![<|>]",
727 r" 335 expect![[r#"
728 #![<|>] 336 at allow(…)
729 ", 337 at cfg(…)
730 ), 338 at cfg_attr(…)
731 @r###" 339 at deny(…)
732 [ 340 at deprecated = "…"
733 CompletionItem { 341 at derive(…)
734 label: "allow(…)", 342 at doc = "…"
735 source_range: 3..3, 343 at feature(…)
736 delete: 3..3, 344 at forbid(…)
737 insert: "allow(${0:lint})", 345 at global_allocator
738 kind: Attribute, 346 at ignore(…)
739 lookup: "allow", 347 at inline(…)
740 }, 348 at link
741 CompletionItem { 349 at link_name = "…"
742 label: "cfg(…)", 350 at macro_export
743 source_range: 3..3, 351 at macro_use
744 delete: 3..3, 352 at must_use = "…"
745 insert: "cfg(${0:predicate})", 353 at no_mangle
746 kind: Attribute, 354 at no_std
747 lookup: "cfg", 355 at non_exhaustive
748 }, 356 at panic_handler
749 CompletionItem { 357 at path = "…"
750 label: "cfg_attr(…)", 358 at proc_macro
751 source_range: 3..3, 359 at proc_macro_attribute
752 delete: 3..3, 360 at proc_macro_derive(…)
753 insert: "cfg_attr(${1:predicate}, ${0:attr})", 361 at recursion_limit = …
754 kind: Attribute, 362 at repr(…)
755 lookup: "cfg_attr", 363 at should_panic(…)
756 }, 364 at target_feature = "…"
757 CompletionItem { 365 at test
758 label: "deny(…)", 366 at used
759 source_range: 3..3, 367 at warn(…)
760 delete: 3..3, 368 at windows_subsystem = "…"
761 insert: "deny(${0:lint})", 369 "#]],
762 kind: Attribute,
763 lookup: "deny",
764 },
765 CompletionItem {
766 label: "deprecated = \"…\"",
767 source_range: 3..3,
768 delete: 3..3,
769 insert: "deprecated = \"${0:reason}\"",
770 kind: Attribute,
771 lookup: "deprecated",
772 },
773 CompletionItem {
774 label: "derive(…)",
775 source_range: 3..3,
776 delete: 3..3,
777 insert: "derive(${0:Debug})",
778 kind: Attribute,
779 lookup: "derive",
780 },
781 CompletionItem {
782 label: "doc = \"…\"",
783 source_range: 3..3,
784 delete: 3..3,
785 insert: "doc = \"${0:docs}\"",
786 kind: Attribute,
787 lookup: "doc",
788 },
789 CompletionItem {
790 label: "feature(…)",
791 source_range: 3..3,
792 delete: 3..3,
793 insert: "feature(${0:flag})",
794 kind: Attribute,
795 lookup: "feature",
796 },
797 CompletionItem {
798 label: "forbid(…)",
799 source_range: 3..3,
800 delete: 3..3,
801 insert: "forbid(${0:lint})",
802 kind: Attribute,
803 lookup: "forbid",
804 },
805 CompletionItem {
806 label: "global_allocator",
807 source_range: 3..3,
808 delete: 3..3,
809 insert: "global_allocator",
810 kind: Attribute,
811 },
812 CompletionItem {
813 label: "ignore(…)",
814 source_range: 3..3,
815 delete: 3..3,
816 insert: "ignore(${0:lint})",
817 kind: Attribute,
818 lookup: "ignore",
819 },
820 CompletionItem {
821 label: "inline(…)",
822 source_range: 3..3,
823 delete: 3..3,
824 insert: "inline(${0:lint})",
825 kind: Attribute,
826 lookup: "inline",
827 },
828 CompletionItem {
829 label: "link",
830 source_range: 3..3,
831 delete: 3..3,
832 insert: "link",
833 kind: Attribute,
834 },
835 CompletionItem {
836 label: "link_name = \"…\"",
837 source_range: 3..3,
838 delete: 3..3,
839 insert: "link_name = \"${0:symbol_name}\"",
840 kind: Attribute,
841 lookup: "link_name",
842 },
843 CompletionItem {
844 label: "macro_export",
845 source_range: 3..3,
846 delete: 3..3,
847 insert: "macro_export",
848 kind: Attribute,
849 },
850 CompletionItem {
851 label: "macro_use",
852 source_range: 3..3,
853 delete: 3..3,
854 insert: "macro_use",
855 kind: Attribute,
856 },
857 CompletionItem {
858 label: "must_use = \"…\"",
859 source_range: 3..3,
860 delete: 3..3,
861 insert: "must_use = \"${0:reason}\"",
862 kind: Attribute,
863 lookup: "must_use",
864 },
865 CompletionItem {
866 label: "no_mangle",
867 source_range: 3..3,
868 delete: 3..3,
869 insert: "no_mangle",
870 kind: Attribute,
871 },
872 CompletionItem {
873 label: "no_std",
874 source_range: 3..3,
875 delete: 3..3,
876 insert: "no_std",
877 kind: Attribute,
878 },
879 CompletionItem {
880 label: "non_exhaustive",
881 source_range: 3..3,
882 delete: 3..3,
883 insert: "non_exhaustive",
884 kind: Attribute,
885 },
886 CompletionItem {
887 label: "panic_handler",
888 source_range: 3..3,
889 delete: 3..3,
890 insert: "panic_handler",
891 kind: Attribute,
892 },
893 CompletionItem {
894 label: "path = \"…\"",
895 source_range: 3..3,
896 delete: 3..3,
897 insert: "path =\"${0:path}\"",
898 kind: Attribute,
899 lookup: "path",
900 },
901 CompletionItem {
902 label: "proc_macro",
903 source_range: 3..3,
904 delete: 3..3,
905 insert: "proc_macro",
906 kind: Attribute,
907 },
908 CompletionItem {
909 label: "proc_macro_attribute",
910 source_range: 3..3,
911 delete: 3..3,
912 insert: "proc_macro_attribute",
913 kind: Attribute,
914 },
915 CompletionItem {
916 label: "proc_macro_derive(…)",
917 source_range: 3..3,
918 delete: 3..3,
919 insert: "proc_macro_derive(${0:Trait})",
920 kind: Attribute,
921 lookup: "proc_macro_derive",
922 },
923 CompletionItem {
924 label: "recursion_limit = …",
925 source_range: 3..3,
926 delete: 3..3,
927 insert: "recursion_limit = ${0:128}",
928 kind: Attribute,
929 lookup: "recursion_limit",
930 },
931 CompletionItem {
932 label: "repr(…)",
933 source_range: 3..3,
934 delete: 3..3,
935 insert: "repr(${0:C})",
936 kind: Attribute,
937 lookup: "repr",
938 },
939 CompletionItem {
940 label: "should_panic(…)",
941 source_range: 3..3,
942 delete: 3..3,
943 insert: "should_panic(expected = \"${0:reason}\")",
944 kind: Attribute,
945 lookup: "should_panic",
946 },
947 CompletionItem {
948 label: "target_feature = \"…\"",
949 source_range: 3..3,
950 delete: 3..3,
951 insert: "target_feature = \"${0:feature}\"",
952 kind: Attribute,
953 lookup: "target_feature",
954 },
955 CompletionItem {
956 label: "test",
957 source_range: 3..3,
958 delete: 3..3,
959 insert: "test",
960 kind: Attribute,
961 },
962 CompletionItem {
963 label: "used",
964 source_range: 3..3,
965 delete: 3..3,
966 insert: "used",
967 kind: Attribute,
968 },
969 CompletionItem {
970 label: "warn(…)",
971 source_range: 3..3,
972 delete: 3..3,
973 insert: "warn(${0:lint})",
974 kind: Attribute,
975 lookup: "warn",
976 },
977 CompletionItem {
978 label: "windows_subsystem = \"…\"",
979 source_range: 3..3,
980 delete: 3..3,
981 insert: "windows_subsystem = \"${0:subsystem}\"",
982 kind: Attribute,
983 lookup: "windows_subsystem",
984 },
985 ]
986 "###
987 ); 370 );
988 } 371 }
989} 372}
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index e599cc3d1..086b917ce 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{ast, SyntaxKind}; 3use ra_syntax::{ast, SyntaxKind};
4use test_utils::mark;
4 5
5use crate::completion::{ 6use crate::completion::{
6 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -38,6 +39,7 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
38 39
39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 40pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
40 if ctx.token.kind() == SyntaxKind::COMMENT { 41 if ctx.token.kind() == SyntaxKind::COMMENT {
42 mark::hit!(no_keyword_completion_in_comments);
41 return; 43 return;
42 } 44 }
43 45
@@ -174,289 +176,318 @@ fn complete_return(
174 176
175#[cfg(test)] 177#[cfg(test)]
176mod tests { 178mod tests {
177 use crate::completion::{test_utils::completion_list, CompletionKind}; 179 use expect::{expect, Expect};
178 use insta::assert_snapshot;
179 180
180 fn get_keyword_completions(code: &str) -> String { 181 use crate::completion::{
181 completion_list(code, CompletionKind::Keyword) 182 test_utils::{check_edit, completion_list},
183 CompletionKind,
184 };
185 use test_utils::mark;
186
187 fn check(ra_fixture: &str, expect: Expect) {
188 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
189 expect.assert_eq(&actual)
182 } 190 }
183 191
184 #[test] 192 #[test]
185 fn test_keywords_in_use_stmt() { 193 fn test_keywords_in_use_stmt() {
186 assert_snapshot!( 194 check(
187 get_keyword_completions(r"use <|>"), 195 r"use <|>",
188 @r###" 196 expect![[r#"
189 kw crate:: 197 kw crate::
190 kw self 198 kw self
191 kw super:: 199 kw super::
192 "### 200 "#]],
193 ); 201 );
194 202
195 assert_snapshot!( 203 check(
196 get_keyword_completions(r"use a::<|>"), 204 r"use a::<|>",
197 @r###" 205 expect![[r#"
198 kw self 206 kw self
199 kw super:: 207 kw super::
200 "### 208 "#]],
201 ); 209 );
202 210
203 assert_snapshot!( 211 check(
204 get_keyword_completions(r"use a::{b, <|>}"), 212 r"use a::{b, <|>}",
205 @r###" 213 expect![[r#"
206 kw self 214 kw self
207 kw super:: 215 kw super::
208 "### 216 "#]],
209 ); 217 );
210 } 218 }
211 219
212 #[test] 220 #[test]
213 fn test_keywords_at_source_file_level() { 221 fn test_keywords_at_source_file_level() {
214 assert_snapshot!( 222 check(
215 get_keyword_completions(r"m<|>"), 223 r"m<|>",
216 @r###" 224 expect![[r#"
217 kw const 225 kw const
218 kw enum 226 kw enum
219 kw extern 227 kw extern
220 kw fn 228 kw fn
221 kw impl 229 kw impl
222 kw mod 230 kw mod
223 kw pub 231 kw pub
224 kw static 232 kw static
225 kw struct 233 kw struct
226 kw trait 234 kw trait
227 kw type 235 kw type
228 kw union 236 kw union
229 kw unsafe 237 kw unsafe
230 kw use 238 kw use
231 "### 239 "#]],
232 ); 240 );
233 } 241 }
234 242
235 #[test] 243 #[test]
236 fn test_keywords_in_function() { 244 fn test_keywords_in_function() {
237 assert_snapshot!( 245 check(
238 get_keyword_completions(r"fn quux() { <|> }"), 246 r"fn quux() { <|> }",
239 @r###" 247 expect![[r#"
240 kw const 248 kw const
241 kw extern 249 kw extern
242 kw fn 250 kw fn
243 kw if 251 kw if
244 kw if let 252 kw if let
245 kw impl 253 kw impl
246 kw let 254 kw let
247 kw loop 255 kw loop
248 kw match 256 kw match
249 kw mod 257 kw mod
250 kw return 258 kw return
251 kw static 259 kw static
252 kw trait 260 kw trait
253 kw type 261 kw type
254 kw unsafe 262 kw unsafe
255 kw use 263 kw use
256 kw while 264 kw while
257 "### 265 "#]],
258 ); 266 );
259 } 267 }
260 268
261 #[test] 269 #[test]
262 fn test_keywords_inside_block() { 270 fn test_keywords_inside_block() {
263 assert_snapshot!( 271 check(
264 get_keyword_completions(r"fn quux() { if true { <|> } }"), 272 r"fn quux() { if true { <|> } }",
265 @r###" 273 expect![[r#"
266 kw const 274 kw const
267 kw extern 275 kw extern
268 kw fn 276 kw fn
269 kw if 277 kw if
270 kw if let 278 kw if let
271 kw impl 279 kw impl
272 kw let 280 kw let
273 kw loop 281 kw loop
274 kw match 282 kw match
275 kw mod 283 kw mod
276 kw return 284 kw return
277 kw static 285 kw static
278 kw trait 286 kw trait
279 kw type 287 kw type
280 kw unsafe 288 kw unsafe
281 kw use 289 kw use
282 kw while 290 kw while
283 "### 291 "#]],
284 ); 292 );
285 } 293 }
286 294
287 #[test] 295 #[test]
288 fn test_keywords_after_if() { 296 fn test_keywords_after_if() {
289 assert_snapshot!( 297 check(
290 get_keyword_completions( 298 r#"fn quux() { if true { () } <|> }"#,
291 r" 299 expect![[r#"
292 fn quux() { 300 kw const
293 if true { 301 kw else
294 () 302 kw else if
295 } <|> 303 kw extern
296 } 304 kw fn
297 ", 305 kw if
298 ), 306 kw if let
299 @r###" 307 kw impl
300 kw const 308 kw let
301 kw else 309 kw loop
302 kw else if 310 kw match
303 kw extern 311 kw mod
304 kw fn 312 kw return
305 kw if 313 kw static
306 kw if let 314 kw trait
307 kw impl 315 kw type
308 kw let 316 kw unsafe
309 kw loop 317 kw use
310 kw match 318 kw while
311 kw mod 319 "#]],
312 kw return 320 );
313 kw static 321 check_edit(
314 kw trait 322 "else",
315 kw type 323 r#"fn quux() { if true { () } <|> }"#,
316 kw unsafe 324 r#"fn quux() { if true { () } else {$0} }"#,
317 kw use
318 kw while
319 "###
320 ); 325 );
321 } 326 }
322 327
323 #[test] 328 #[test]
324 fn test_keywords_in_match_arm() { 329 fn test_keywords_in_match_arm() {
325 assert_snapshot!( 330 check(
326 get_keyword_completions( 331 r#"
327 r" 332fn quux() -> i32 {
328 fn quux() -> i32 { 333 match () {
329 match () { 334 () => <|>
330 () => <|> 335 }
331 } 336}
332 } 337"#,
333 ", 338 expect![[r#"
334 ), 339 kw if
335 @r###" 340 kw if let
336 kw if 341 kw loop
337 kw if let 342 kw match
338 kw loop 343 kw return
339 kw match 344 kw unsafe
340 kw return 345 "#]],
341 kw unsafe
342 "###
343 ); 346 );
344 } 347 }
345 348
346 #[test] 349 #[test]
347 fn test_keywords_in_trait_def() { 350 fn test_keywords_in_trait_def() {
348 assert_snapshot!( 351 check(
349 get_keyword_completions(r"trait My { <|> }"), 352 r"trait My { <|> }",
350 @r###" 353 expect![[r#"
351 kw const 354 kw const
352 kw fn 355 kw fn
353 kw type 356 kw type
354 kw unsafe 357 kw unsafe
355 "### 358 "#]],
356 ); 359 );
357 } 360 }
358 361
359 #[test] 362 #[test]
360 fn test_keywords_in_impl_def() { 363 fn test_keywords_in_impl_def() {
361 assert_snapshot!( 364 check(
362 get_keyword_completions(r"impl My { <|> }"), 365 r"impl My { <|> }",
363 @r###" 366 expect![[r#"
364 kw const 367 kw const
365 kw fn 368 kw fn
366 kw pub 369 kw pub
367 kw type 370 kw type
368 kw unsafe 371 kw unsafe
369 "### 372 "#]],
370 ); 373 );
371 } 374 }
372 375
373 #[test] 376 #[test]
374 fn test_keywords_in_loop() { 377 fn test_keywords_in_loop() {
375 assert_snapshot!( 378 check(
376 get_keyword_completions(r"fn my() { loop { <|> } }"), 379 r"fn my() { loop { <|> } }",
377 @r###" 380 expect![[r#"
378 kw break 381 kw break
379 kw const 382 kw const
380 kw continue 383 kw continue
381 kw extern 384 kw extern
382 kw fn 385 kw fn
383 kw if 386 kw if
384 kw if let 387 kw if let
385 kw impl 388 kw impl
386 kw let 389 kw let
387 kw loop 390 kw loop
388 kw match 391 kw match
389 kw mod 392 kw mod
390 kw return 393 kw return
391 kw static 394 kw static
392 kw trait 395 kw trait
393 kw type 396 kw type
394 kw unsafe 397 kw unsafe
395 kw use 398 kw use
396 kw while 399 kw while
397 "### 400 "#]],
398 ); 401 );
399 } 402 }
400 403
401 #[test] 404 #[test]
402 fn test_keywords_after_unsafe_in_item_list() { 405 fn test_keywords_after_unsafe_in_item_list() {
403 assert_snapshot!( 406 check(
404 get_keyword_completions(r"unsafe <|>"), 407 r"unsafe <|>",
405 @r###" 408 expect![[r#"
406 kw fn 409 kw fn
407 kw impl 410 kw impl
408 kw trait 411 kw trait
409 "### 412 "#]],
410 ); 413 );
411 } 414 }
412 415
413 #[test] 416 #[test]
414 fn test_keywords_after_unsafe_in_block_expr() { 417 fn test_keywords_after_unsafe_in_block_expr() {
415 assert_snapshot!( 418 check(
416 get_keyword_completions(r"fn my_fn() { unsafe <|> }"), 419 r"fn my_fn() { unsafe <|> }",
417 @r###" 420 expect![[r#"
418 kw fn 421 kw fn
419 kw impl 422 kw impl
420 kw trait 423 kw trait
421 "### 424 "#]],
422 ); 425 );
423 } 426 }
424 427
425 #[test] 428 #[test]
426 fn test_mut_in_ref_and_in_fn_parameters_list() { 429 fn test_mut_in_ref_and_in_fn_parameters_list() {
427 assert_snapshot!( 430 check(
428 get_keyword_completions(r"fn my_fn(&<|>) {}"), 431 r"fn my_fn(&<|>) {}",
429 @r###" 432 expect![[r#"
430 kw mut 433 kw mut
431 "### 434 "#]],
432 ); 435 );
433 assert_snapshot!( 436 check(
434 get_keyword_completions(r"fn my_fn(<|>) {}"), 437 r"fn my_fn(<|>) {}",
435 @r###" 438 expect![[r#"
436 kw mut 439 kw mut
437 "### 440 "#]],
438 ); 441 );
439 assert_snapshot!( 442 check(
440 get_keyword_completions(r"fn my_fn() { let &<|> }"), 443 r"fn my_fn() { let &<|> }",
441 @r###" 444 expect![[r#"
442 kw mut 445 kw mut
443 "### 446 "#]],
444 ); 447 );
445 } 448 }
446 449
447 #[test] 450 #[test]
448 fn test_where_keyword() { 451 fn test_where_keyword() {
449 assert_snapshot!( 452 check(
450 get_keyword_completions(r"trait A <|>"), 453 r"trait A <|>",
451 @r###" 454 expect![[r#"
452 kw where 455 kw where
453 "### 456 "#]],
457 );
458 check(
459 r"impl A <|>",
460 expect![[r#"
461 kw where
462 "#]],
463 );
464 }
465
466 #[test]
467 fn no_keyword_completion_in_comments() {
468 mark::check!(no_keyword_completion_in_comments);
469 check(
470 r#"
471fn test() {
472 let x = 2; // A comment<|>
473}
474"#,
475 expect![[""]],
476 );
477 check(
478 r#"
479/*
480Some multi-line comment<|>
481*/
482"#,
483 expect![[""]],
454 ); 484 );
455 assert_snapshot!( 485 check(
456 get_keyword_completions(r"impl A <|>"), 486 r#"
457 @r###" 487/// Some doc comment
458 kw where 488/// let test<|> = 1
459 "### 489"#,
490 expect![[""]],
460 ); 491 );
461 } 492 }
462} 493}
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
index 13eb2f79f..74b94594d 100644
--- a/crates/ra_ide/src/completion/complete_record.rs
+++ b/crates/ra_ide/src/completion/complete_record.rs
@@ -18,389 +18,209 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
18 18
19#[cfg(test)] 19#[cfg(test)]
20mod tests { 20mod tests {
21 mod record_pat_tests { 21 use expect::{expect, Expect};
22 use insta::assert_debug_snapshot;
23 22
24 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 23 use crate::completion::{test_utils::completion_list, CompletionKind};
25 24
26 fn complete(code: &str) -> Vec<CompletionItem> { 25 fn check(ra_fixture: &str, expect: Expect) {
27 do_completion(code, CompletionKind::Reference) 26 let actual = completion_list(ra_fixture, CompletionKind::Reference);
28 } 27 expect.assert_eq(&actual);
29 28 }
30 #[test]
31 fn test_record_pattern_field() {
32 let completions = complete(
33 r"
34 struct S { foo: u32 }
35
36 fn process(f: S) {
37 match f {
38 S { f<|>: 92 } => (),
39 }
40 }
41 ",
42 );
43 assert_debug_snapshot!(completions, @r###"
44 [
45 CompletionItem {
46 label: "foo",
47 source_range: 68..69,
48 delete: 68..69,
49 insert: "foo",
50 kind: Field,
51 detail: "u32",
52 },
53 ]
54 "###);
55 }
56
57 #[test]
58 fn test_record_pattern_enum_variant() {
59 let completions = complete(
60 r"
61 enum E {
62 S { foo: u32, bar: () }
63 }
64
65 fn process(e: E) {
66 match e {
67 E::S { <|> } => (),
68 }
69 }
70 ",
71 );
72 assert_debug_snapshot!(completions, @r###"
73 [
74 CompletionItem {
75 label: "bar",
76 source_range: 88..88,
77 delete: 88..88,
78 insert: "bar",
79 kind: Field,
80 detail: "()",
81 },
82 CompletionItem {
83 label: "foo",
84 source_range: 88..88,
85 delete: 88..88,
86 insert: "foo",
87 kind: Field,
88 detail: "u32",
89 },
90 ]
91 "###);
92 }
93 29
94 #[test] 30 #[test]
95 fn test_record_pattern_field_in_simple_macro() { 31 fn test_record_pattern_field() {
96 let completions = complete( 32 check(
97 r" 33 r#"
98 macro_rules! m { ($e:expr) => { $e } } 34struct S { foo: u32 }
99 struct S { foo: u32 }
100 35
101 fn process(f: S) { 36fn process(f: S) {
102 m!(match f { 37 match f {
103 S { f<|>: 92 } => (), 38 S { f<|>: 92 } => (),
104 }) 39 }
105 } 40}
106 ", 41"#,
107 ); 42 expect![[r#"
108 assert_debug_snapshot!(completions, @r###" 43 fd foo u32
109 [ 44 "#]],
110 CompletionItem { 45 );
111 label: "foo", 46 }
112 source_range: 110..111,
113 delete: 110..111,
114 insert: "foo",
115 kind: Field,
116 detail: "u32",
117 },
118 ]
119 "###);
120 }
121 47
122 #[test] 48 #[test]
123 fn only_missing_fields_are_completed_in_destruct_pats() { 49 fn test_record_pattern_enum_variant() {
124 let completions = complete( 50 check(
125 r" 51 r#"
126 struct S { 52enum E { S { foo: u32, bar: () } }
127 foo1: u32,
128 foo2: u32,
129 bar: u32,
130 baz: u32,
131 }
132 53
133 fn main() { 54fn process(e: E) {
134 let s = S { 55 match e {
135 foo1: 1, 56 E::S { <|> } => (),
136 foo2: 2, 57 }
137 bar: 3, 58}
138 baz: 4, 59"#,
139 }; 60 expect![[r#"
140 if let S { foo1, foo2: a, <|> } = s {} 61 fd bar ()
141 } 62 fd foo u32
142 ", 63 "#]],
143 ); 64 );
144 assert_debug_snapshot!(completions, @r###"
145 [
146 CompletionItem {
147 label: "bar",
148 source_range: 203..203,
149 delete: 203..203,
150 insert: "bar",
151 kind: Field,
152 detail: "u32",
153 },
154 CompletionItem {
155 label: "baz",
156 source_range: 203..203,
157 delete: 203..203,
158 insert: "baz",
159 kind: Field,
160 detail: "u32",
161 },
162 ]
163 "###);
164 }
165 } 65 }
166 66
167 mod record_lit_tests { 67 #[test]
168 use insta::assert_debug_snapshot; 68 fn test_record_pattern_field_in_simple_macro() {
169 69 check(
170 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 r"
71macro_rules! m { ($e:expr) => { $e } }
72struct S { foo: u32 }
73
74fn process(f: S) {
75 m!(match f {
76 S { f<|>: 92 } => (),
77 })
78}
79",
80 expect![[r#"
81 fd foo u32
82 "#]],
83 );
84 }
171 85
172 fn complete(code: &str) -> Vec<CompletionItem> { 86 #[test]
173 do_completion(code, CompletionKind::Reference) 87 fn only_missing_fields_are_completed_in_destruct_pats() {
174 } 88 check(
89 r#"
90struct S {
91 foo1: u32, foo2: u32,
92 bar: u32, baz: u32,
93}
175 94
176 #[test] 95fn main() {
177 fn test_record_literal_deprecated_field() { 96 let s = S {
178 let completions = complete( 97 foo1: 1, foo2: 2,
179 r" 98 bar: 3, baz: 4,
180 struct A { 99 };
181 #[deprecated] 100 if let S { foo1, foo2: a, <|> } = s {}
182 the_field: u32, 101}
183 } 102"#,
184 fn foo() { 103 expect![[r#"
185 A { the<|> } 104 fd bar u32
186 } 105 fd baz u32
187 ", 106 "#]],
188 ); 107 );
189 assert_debug_snapshot!(completions, @r###" 108 }
190 [
191 CompletionItem {
192 label: "the_field",
193 source_range: 69..72,
194 delete: 69..72,
195 insert: "the_field",
196 kind: Field,
197 detail: "u32",
198 deprecated: true,
199 },
200 ]
201 "###);
202 }
203 109
204 #[test] 110 #[test]
205 fn test_record_literal_field() { 111 fn test_record_literal_field() {
206 let completions = complete( 112 check(
207 r" 113 r#"
208 struct A { the_field: u32 } 114struct A { the_field: u32 }
209 fn foo() { 115fn foo() {
210 A { the<|> } 116 A { the<|> }
211 } 117}
212 ", 118"#,
213 ); 119 expect![[r#"
214 assert_debug_snapshot!(completions, @r###" 120 fd the_field u32
215 [ 121 "#]],
216 CompletionItem { 122 );
217 label: "the_field", 123 }
218 source_range: 46..49,
219 delete: 46..49,
220 insert: "the_field",
221 kind: Field,
222 detail: "u32",
223 },
224 ]
225 "###);
226 }
227 124
228 #[test] 125 #[test]
229 fn test_record_literal_enum_variant() { 126 fn test_record_literal_enum_variant() {
230 let completions = complete( 127 check(
231 r" 128 r#"
232 enum E { 129enum E { A { a: u32 } }
233 A { a: u32 } 130fn foo() {
234 } 131 let _ = E::A { <|> }
235 fn foo() { 132}
236 let _ = E::A { <|> } 133"#,
237 } 134 expect![[r#"
238 ", 135 fd a u32
239 ); 136 "#]],
240 assert_debug_snapshot!(completions, @r###" 137 );
241 [ 138 }
242 CompletionItem {
243 label: "a",
244 source_range: 58..58,
245 delete: 58..58,
246 insert: "a",
247 kind: Field,
248 detail: "u32",
249 },
250 ]
251 "###);
252 }
253 139
254 #[test] 140 #[test]
255 fn test_record_literal_two_structs() { 141 fn test_record_literal_two_structs() {
256 let completions = complete( 142 check(
257 r" 143 r#"
258 struct A { a: u32 } 144struct A { a: u32 }
259 struct B { b: u32 } 145struct B { b: u32 }
260 146
261 fn foo() { 147fn foo() {
262 let _: A = B { <|> } 148 let _: A = B { <|> }
263 } 149}
264 ", 150"#,
265 ); 151 expect![[r#"
266 assert_debug_snapshot!(completions, @r###" 152 fd b u32
267 [ 153 "#]],
268 CompletionItem { 154 );
269 label: "b", 155 }
270 source_range: 70..70,
271 delete: 70..70,
272 insert: "b",
273 kind: Field,
274 detail: "u32",
275 },
276 ]
277 "###);
278 }
279 156
280 #[test] 157 #[test]
281 fn test_record_literal_generic_struct() { 158 fn test_record_literal_generic_struct() {
282 let completions = complete( 159 check(
283 r" 160 r#"
284 struct A<T> { a: T } 161struct A<T> { a: T }
285 162
286 fn foo() { 163fn foo() {
287 let _: A<u32> = A { <|> } 164 let _: A<u32> = A { <|> }
288 } 165}
289 ", 166"#,
290 ); 167 expect![[r#"
291 assert_debug_snapshot!(completions, @r###" 168 fd a u32
292 [ 169 "#]],
293 CompletionItem { 170 );
294 label: "a", 171 }
295 source_range: 56..56,
296 delete: 56..56,
297 insert: "a",
298 kind: Field,
299 detail: "u32",
300 },
301 ]
302 "###);
303 }
304 172
305 #[test] 173 #[test]
306 fn test_record_literal_field_in_simple_macro() { 174 fn test_record_literal_field_in_simple_macro() {
307 let completions = complete( 175 check(
308 r" 176 r#"
309 macro_rules! m { ($e:expr) => { $e } } 177macro_rules! m { ($e:expr) => { $e } }
310 struct A { the_field: u32 } 178struct A { the_field: u32 }
311 fn foo() { 179fn foo() {
312 m!(A { the<|> }) 180 m!(A { the<|> })
313 } 181}
314 ", 182"#,
315 ); 183 expect![[r#"
316 assert_debug_snapshot!(completions, @r###" 184 fd the_field u32
317 [ 185 "#]],
318 CompletionItem { 186 );
319 label: "the_field", 187 }
320 source_range: 88..91,
321 delete: 88..91,
322 insert: "the_field",
323 kind: Field,
324 detail: "u32",
325 },
326 ]
327 "###);
328 }
329 188
330 #[test] 189 #[test]
331 fn only_missing_fields_are_completed() { 190 fn only_missing_fields_are_completed() {
332 let completions = complete( 191 check(
333 r" 192 r#"
334 struct S { 193struct S {
335 foo1: u32, 194 foo1: u32, foo2: u32,
336 foo2: u32, 195 bar: u32, baz: u32,
337 bar: u32, 196}
338 baz: u32,
339 }
340 197
341 fn main() { 198fn main() {
342 let foo1 = 1; 199 let foo1 = 1;
343 let s = S { 200 let s = S { foo1, foo2: 5, <|> }
344 foo1, 201}
345 foo2: 5, 202"#,
346 <|> 203 expect![[r#"
347 } 204 fd bar u32
348 } 205 fd baz u32
349 ", 206 "#]],
350 ); 207 );
351 assert_debug_snapshot!(completions, @r###" 208 }
352 [
353 CompletionItem {
354 label: "bar",
355 source_range: 157..157,
356 delete: 157..157,
357 insert: "bar",
358 kind: Field,
359 detail: "u32",
360 },
361 CompletionItem {
362 label: "baz",
363 source_range: 157..157,
364 delete: 157..157,
365 insert: "baz",
366 kind: Field,
367 detail: "u32",
368 },
369 ]
370 "###);
371 }
372 209
373 #[test] 210 #[test]
374 fn completes_functional_update() { 211 fn completes_functional_update() {
375 let completions = complete( 212 check(
376 r" 213 r#"
377 struct S { 214struct S { foo1: u32, foo2: u32 }
378 foo1: u32,
379 foo2: u32,
380 }
381 215
382 fn main() { 216fn main() {
383 let foo1 = 1; 217 let foo1 = 1;
384 let s = S { 218 let s = S { foo1, <|> .. loop {} }
385 foo1, 219}
386 <|> 220"#,
387 .. loop {} 221 expect![[r#"
388 } 222 fd foo2 u32
389 } 223 "#]],
390 ", 224 );
391 );
392 assert_debug_snapshot!(completions, @r###"
393 [
394 CompletionItem {
395 label: "foo2",
396 source_range: 112..112,
397 delete: 112..112,
398 insert: "foo2",
399 kind: Field,
400 detail: "u32",
401 },
402 ]
403 "###);
404 }
405 } 225 }
406} 226}
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index 98348b349..4db371d57 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -129,24 +129,24 @@ impl CompletionItemKind {
129 #[cfg(test)] 129 #[cfg(test)]
130 pub(crate) fn tag(&self) -> &'static str { 130 pub(crate) fn tag(&self) -> &'static str {
131 match self { 131 match self {
132 CompletionItemKind::Snippet => "sn", 132 CompletionItemKind::Attribute => "at",
133 CompletionItemKind::Keyword => "kw", 133 CompletionItemKind::Binding => "bn",
134 CompletionItemKind::Module => "md",
135 CompletionItemKind::Function => "fn",
136 CompletionItemKind::BuiltinType => "bt", 134 CompletionItemKind::BuiltinType => "bt",
137 CompletionItemKind::Struct => "st", 135 CompletionItemKind::Const => "ct",
138 CompletionItemKind::Enum => "en", 136 CompletionItemKind::Enum => "en",
139 CompletionItemKind::EnumVariant => "ev", 137 CompletionItemKind::EnumVariant => "ev",
140 CompletionItemKind::Binding => "bn",
141 CompletionItemKind::Field => "fd", 138 CompletionItemKind::Field => "fd",
139 CompletionItemKind::Function => "fn",
140 CompletionItemKind::Keyword => "kw",
141 CompletionItemKind::Macro => "ma",
142 CompletionItemKind::Method => "me",
143 CompletionItemKind::Module => "md",
144 CompletionItemKind::Snippet => "sn",
142 CompletionItemKind::Static => "sc", 145 CompletionItemKind::Static => "sc",
143 CompletionItemKind::Const => "ct", 146 CompletionItemKind::Struct => "st",
144 CompletionItemKind::Trait => "tt", 147 CompletionItemKind::Trait => "tt",
145 CompletionItemKind::TypeAlias => "ta", 148 CompletionItemKind::TypeAlias => "ta",
146 CompletionItemKind::Method => "me",
147 CompletionItemKind::TypeParam => "tp", 149 CompletionItemKind::TypeParam => "tp",
148 CompletionItemKind::Macro => "ma",
149 CompletionItemKind::Attribute => "at",
150 } 150 }
151 } 151 }
152} 152}
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index b18279746..fd12673b2 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -383,12 +383,14 @@ impl Builder {
383 return self; 383 return self;
384 } 384 }
385 if ctx.use_item_syntax.is_some() || ctx.is_call { 385 if ctx.use_item_syntax.is_some() || ctx.is_call {
386 mark::hit!(no_parens_in_use_item);
386 return self; 387 return self;
387 } 388 }
388 389
389 // Don't add parentheses if the expected type is some function reference. 390 // Don't add parentheses if the expected type is some function reference.
390 if let Some(ty) = &ctx.expected_type { 391 if let Some(ty) = &ctx.expected_type {
391 if ty.is_fn() { 392 if ty.is_fn() {
393 mark::hit!(no_call_parens_if_fn_ptr_needed);
392 return self; 394 return self;
393 } 395 }
394 } 396 }
@@ -413,7 +415,10 @@ impl Builder {
413 .sep_by(", "); 415 .sep_by(", ");
414 format!("{}({})$0", name, function_params_snippet) 416 format!("{}({})$0", name, function_params_snippet)
415 } 417 }
416 _ => format!("{}($0)", name), 418 _ => {
419 mark::hit!(suppress_arg_snippets);
420 format!("{}($0)", name)
421 }
417 }; 422 };
418 423
419 (snippet, format!("{}(…)", name)) 424 (snippet, format!("{}(…)", name))
@@ -460,7 +465,7 @@ mod tests {
460 use test_utils::mark; 465 use test_utils::mark;
461 466
462 use crate::completion::{ 467 use crate::completion::{
463 test_utils::{do_completion, do_completion_with_options}, 468 test_utils::{check_edit, check_edit_with_config, do_completion},
464 CompletionConfig, CompletionItem, CompletionKind, 469 CompletionConfig, CompletionItem, CompletionKind,
465 }; 470 };
466 471
@@ -468,13 +473,6 @@ mod tests {
468 do_completion(ra_fixture, CompletionKind::Reference) 473 do_completion(ra_fixture, CompletionKind::Reference)
469 } 474 }
470 475
471 fn do_reference_completion_with_options(
472 ra_fixture: &str,
473 options: CompletionConfig,
474 ) -> Vec<CompletionItem> {
475 do_completion_with_options(ra_fixture, CompletionKind::Reference, &options)
476 }
477
478 #[test] 476 #[test]
479 fn enum_detail_includes_names_for_record() { 477 fn enum_detail_includes_names_for_record() {
480 assert_debug_snapshot!( 478 assert_debug_snapshot!(
@@ -606,448 +604,240 @@ mod tests {
606 ] 604 ]
607 "### 605 "###
608 ); 606 );
609 }
610 607
611 #[test] 608 assert_debug_snapshot!(do_reference_completion(
612 fn inserts_parens_for_function_calls() { 609 r#"
613 mark::check!(inserts_parens_for_function_calls); 610struct A {
614 assert_debug_snapshot!( 611 #[deprecated]
615 do_reference_completion( 612 the_field: u32,
616 r" 613}
617 fn no_args() {} 614fn foo() {
618 fn main() { no_<|> } 615 A { the<|> }
619 " 616}
620 ), 617"#,
621 @r###" 618 ),
622 [ 619 @r###"
623 CompletionItem {
624 label: "main()",
625 source_range: 28..31,
626 delete: 28..31,
627 insert: "main()$0",
628 kind: Function,
629 lookup: "main",
630 detail: "fn main()",
631 },
632 CompletionItem {
633 label: "no_args()",
634 source_range: 28..31,
635 delete: 28..31,
636 insert: "no_args()$0",
637 kind: Function,
638 lookup: "no_args",
639 detail: "fn no_args()",
640 },
641 ]
642 "###
643 );
644 assert_debug_snapshot!(
645 do_reference_completion(
646 r"
647 fn with_args(x: i32, y: String) {}
648 fn main() { with_<|> }
649 "
650 ),
651 @r###"
652 [ 620 [
653 CompletionItem { 621 CompletionItem {
654 label: "main()", 622 label: "the_field",
655 source_range: 47..52, 623 source_range: 69..72,
656 delete: 47..52, 624 delete: 69..72,
657 insert: "main()$0", 625 insert: "the_field",
658 kind: Function, 626 kind: Field,
659 lookup: "main", 627 detail: "u32",
660 detail: "fn main()", 628 deprecated: true,
661 },
662 CompletionItem {
663 label: "with_args(…)",
664 source_range: 47..52,
665 delete: 47..52,
666 insert: "with_args(${1:x}, ${2:y})$0",
667 kind: Function,
668 lookup: "with_args",
669 detail: "fn with_args(x: i32, y: String)",
670 trigger_call_info: true,
671 }, 629 },
672 ] 630 ]
673 "### 631 "###);
632 }
633
634 #[test]
635 fn inserts_parens_for_function_calls() {
636 mark::check!(inserts_parens_for_function_calls);
637 check_edit(
638 "no_args",
639 r#"
640fn no_args() {}
641fn main() { no_<|> }
642"#,
643 r#"
644fn no_args() {}
645fn main() { no_args()$0 }
646"#,
674 ); 647 );
675 assert_debug_snapshot!( 648
676 do_reference_completion( 649 check_edit(
677 r" 650 "with_args",
678 fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String) {} 651 r#"
679 fn main() { with_<|> } 652fn with_args(x: i32, y: String) {}
680 " 653fn main() { with_<|> }
681 ), 654"#,
682 @r###" 655 r#"
683 [ 656fn with_args(x: i32, y: String) {}
684 CompletionItem { 657fn main() { with_args(${1:x}, ${2:y})$0 }
685 label: "main()", 658"#,
686 source_range: 77..82,
687 delete: 77..82,
688 insert: "main()$0",
689 kind: Function,
690 lookup: "main",
691 detail: "fn main()",
692 },
693 CompletionItem {
694 label: "with_ignored_args(…)",
695 source_range: 77..82,
696 delete: 77..82,
697 insert: "with_ignored_args(${1:foo}, ${2:bar}, ${3:ho_ge_})$0",
698 kind: Function,
699 lookup: "with_ignored_args",
700 detail: "fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String)",
701 trigger_call_info: true,
702 },
703 ]
704 "###
705 ); 659 );
706 assert_debug_snapshot!( 660
707 do_reference_completion( 661 check_edit(
708 r" 662 "foo",
709 struct S {} 663 r#"
710 impl S { 664struct S;
711 fn foo(&self) {} 665impl S {
712 } 666 fn foo(&self) {}
713 fn bar(s: &S) { 667}
714 s.f<|> 668fn bar(s: &S) { s.f<|> }
715 } 669"#,
716 " 670 r#"
717 ), 671struct S;
718 @r###" 672impl S {
719 [ 673 fn foo(&self) {}
720 CompletionItem { 674}
721 label: "foo()", 675fn bar(s: &S) { s.foo()$0 }
722 source_range: 66..67, 676"#,
723 delete: 66..67,
724 insert: "foo()$0",
725 kind: Method,
726 lookup: "foo",
727 detail: "fn foo(&self)",
728 },
729 ]
730 "###
731 ); 677 );
732 assert_debug_snapshot!( 678
733 do_reference_completion( 679 check_edit(
734 r" 680 "foo",
735 struct S {} 681 r#"
736 impl S { 682struct S {}
737 fn foo_ignored_args(&self, _a: bool, b: i32) {} 683impl S {
738 } 684 fn foo(&self, x: i32) {}
739 fn bar(s: &S) { 685}
740 s.f<|> 686fn bar(s: &S) {
741 } 687 s.f<|>
742 " 688}
743 ), 689"#,
744 @r###" 690 r#"
745 [ 691struct S {}
746 CompletionItem { 692impl S {
747 label: "foo_ignored_args(…)", 693 fn foo(&self, x: i32) {}
748 source_range: 97..98, 694}
749 delete: 97..98, 695fn bar(s: &S) {
750 insert: "foo_ignored_args(${1:a}, ${2:b})$0", 696 s.foo(${1:x})$0
751 kind: Method, 697}
752 lookup: "foo_ignored_args", 698"#,
753 detail: "fn foo_ignored_args(&self, _a: bool, b: i32)",
754 trigger_call_info: true,
755 },
756 ]
757 "###
758 ); 699 );
759 } 700 }
760 701
761 #[test] 702 #[test]
762 fn inserts_parens_for_tuple_enums() { 703 fn suppress_arg_snippets() {
763 assert_debug_snapshot!( 704 mark::check!(suppress_arg_snippets);
764 do_reference_completion( 705 check_edit_with_config(
765 r" 706 "with_args",
766 enum Option<T> { Some(T), None } 707 r#"
767 use Option::*; 708fn with_args(x: i32, y: String) {}
768 fn main() -> Option<i32> { 709fn main() { with_<|> }
769 Som<|> 710"#,
770 } 711 r#"
771 " 712fn with_args(x: i32, y: String) {}
772 ), 713fn main() { with_args($0) }
773 @r###" 714"#,
774 [ 715 &CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
775 CompletionItem {
776 label: "None",
777 source_range: 79..82,
778 delete: 79..82,
779 insert: "None",
780 kind: EnumVariant,
781 detail: "()",
782 },
783 CompletionItem {
784 label: "Option",
785 source_range: 79..82,
786 delete: 79..82,
787 insert: "Option",
788 kind: Enum,
789 },
790 CompletionItem {
791 label: "Some(…)",
792 source_range: 79..82,
793 delete: 79..82,
794 insert: "Some($0)",
795 kind: EnumVariant,
796 lookup: "Some",
797 detail: "(T)",
798 trigger_call_info: true,
799 },
800 CompletionItem {
801 label: "main()",
802 source_range: 79..82,
803 delete: 79..82,
804 insert: "main()$0",
805 kind: Function,
806 lookup: "main",
807 detail: "fn main() -> Option<i32>",
808 },
809 ]
810 "###
811 );
812 assert_debug_snapshot!(
813 do_reference_completion(
814 r"
815 enum Option<T> { Some(T), None }
816 use Option::*;
817 fn main(value: Option<i32>) {
818 match value {
819 Som<|>
820 }
821 }
822 "
823 ),
824 @r###"
825 [
826 CompletionItem {
827 label: "None",
828 source_range: 104..107,
829 delete: 104..107,
830 insert: "None",
831 kind: EnumVariant,
832 detail: "()",
833 },
834 CompletionItem {
835 label: "Option",
836 source_range: 104..107,
837 delete: 104..107,
838 insert: "Option",
839 kind: Enum,
840 },
841 CompletionItem {
842 label: "Some(…)",
843 source_range: 104..107,
844 delete: 104..107,
845 insert: "Some($0)",
846 kind: EnumVariant,
847 lookup: "Some",
848 detail: "(T)",
849 trigger_call_info: true,
850 },
851 ]
852 "###
853 ); 716 );
854 } 717 }
855 718
856 #[test] 719 #[test]
857 fn no_call_parens_if_fn_ptr_needed() { 720 fn strips_underscores_from_args() {
858 assert_debug_snapshot!( 721 check_edit(
859 do_reference_completion( 722 "foo",
860 r" 723 r#"
861 fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8) {} 724fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
862 725fn main() { f<|> }
863 struct ManualVtable { 726"#,
864 method: fn(u8, u8, u8, u8, u8), 727 r#"
865 } 728fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
866 729fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
867 fn main() -> ManualVtable { 730"#,
868 ManualVtable {
869 method: some<|>
870 }
871 }
872 "
873 ),
874 @r###"
875 [
876 CompletionItem {
877 label: "ManualVtable",
878 source_range: 182..186,
879 delete: 182..186,
880 insert: "ManualVtable",
881 kind: Struct,
882 },
883 CompletionItem {
884 label: "main",
885 source_range: 182..186,
886 delete: 182..186,
887 insert: "main",
888 kind: Function,
889 detail: "fn main() -> ManualVtable",
890 },
891 CompletionItem {
892 label: "somefn",
893 source_range: 182..186,
894 delete: 182..186,
895 insert: "somefn",
896 kind: Function,
897 detail: "fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8)",
898 },
899 ]
900 "###
901 ); 731 );
902 } 732 }
903 733
904 #[test] 734 #[test]
905 fn arg_snippets_for_method_call() { 735 fn inserts_parens_for_tuple_enums() {
906 assert_debug_snapshot!( 736 check_edit(
907 do_reference_completion( 737 "Some",
908 r" 738 r#"
909 struct S {} 739enum Option<T> { Some(T), None }
910 impl S { 740use Option::*;
911 fn foo(&self, x: i32) {} 741fn main() -> Option<i32> {
912 } 742 Som<|>
913 fn bar(s: &S) { 743}
914 s.f<|> 744"#,
915 } 745 r#"
916 " 746enum Option<T> { Some(T), None }
917 ), 747use Option::*;
918 @r###" 748fn main() -> Option<i32> {
919 [ 749 Some($0)
920 CompletionItem { 750}
921 label: "foo(…)", 751"#,
922 source_range: 74..75, 752 );
923 delete: 74..75, 753 check_edit(
924 insert: "foo(${1:x})$0", 754 "Some",
925 kind: Method, 755 r#"
926 lookup: "foo", 756enum Option<T> { Some(T), None }
927 detail: "fn foo(&self, x: i32)", 757use Option::*;
928 trigger_call_info: true, 758fn main(value: Option<i32>) {
929 }, 759 match value {
930 ] 760 Som<|>
931 "### 761 }
932 ) 762}
763"#,
764 r#"
765enum Option<T> { Some(T), None }
766use Option::*;
767fn main(value: Option<i32>) {
768 match value {
769 Some($0)
770 }
771}
772"#,
773 );
933 } 774 }
934 775
935 #[test] 776 #[test]
936 fn no_arg_snippets_for_method_call() { 777 fn no_call_parens_if_fn_ptr_needed() {
937 assert_debug_snapshot!( 778 mark::check!(no_call_parens_if_fn_ptr_needed);
938 do_reference_completion_with_options( 779 check_edit(
939 r" 780 "foo",
940 struct S {} 781 r#"
941 impl S { 782fn foo(foo: u8, bar: u8) {}
942 fn foo(&self, x: i32) {} 783struct ManualVtable { f: fn(u8, u8) }
943 } 784
944 fn bar(s: &S) { 785fn main() -> ManualVtable {
945 s.f<|> 786 ManualVtable { f: f<|> }
946 } 787}
947 ", 788"#,
948 CompletionConfig { 789 r#"
949 add_call_argument_snippets: false, 790fn foo(foo: u8, bar: u8) {}
950 .. Default::default() 791struct ManualVtable { f: fn(u8, u8) }
951 } 792
952 ), 793fn main() -> ManualVtable {
953 @r###" 794 ManualVtable { f: foo }
954 [ 795}
955 CompletionItem { 796"#,
956 label: "foo(…)", 797 );
957 source_range: 74..75,
958 delete: 74..75,
959 insert: "foo($0)",
960 kind: Method,
961 lookup: "foo",
962 detail: "fn foo(&self, x: i32)",
963 trigger_call_info: true,
964 },
965 ]
966 "###
967 )
968 } 798 }
969 799
970 #[test] 800 #[test]
971 fn dont_render_function_parens_in_use_item() { 801 fn no_parens_in_use_item() {
972 assert_debug_snapshot!( 802 mark::check!(no_parens_in_use_item);
973 do_reference_completion( 803 check_edit(
974 " 804 "foo",
975 //- /lib.rs 805 r#"
976 mod m { pub fn foo() {} } 806mod m { pub fn foo() {} }
977 use crate::m::f<|>; 807use crate::m::f<|>;
978 " 808"#,
979 ), 809 r#"
980 @r###" 810mod m { pub fn foo() {} }
981 [ 811use crate::m::foo;
982 CompletionItem { 812"#,
983 label: "foo",
984 source_range: 40..41,
985 delete: 40..41,
986 insert: "foo",
987 kind: Function,
988 detail: "pub fn foo()",
989 },
990 ]
991 "###
992 ); 813 );
993 } 814 }
994 815
995 #[test] 816 #[test]
996 fn dont_render_function_parens_if_already_call() { 817 fn no_parens_in_call() {
997 assert_debug_snapshot!( 818 check_edit(
998 do_reference_completion( 819 "foo",
999 " 820 r#"
1000 //- /lib.rs 821fn foo(x: i32) {}
1001 fn frobnicate() {} 822fn main() { f<|>(); }
1002 fn main() { 823"#,
1003 frob<|>(); 824 r#"
1004 } 825fn foo(x: i32) {}
1005 " 826fn main() { foo(); }
1006 ), 827"#,
1007 @r###"
1008 [
1009 CompletionItem {
1010 label: "frobnicate",
1011 source_range: 35..39,
1012 delete: 35..39,
1013 insert: "frobnicate",
1014 kind: Function,
1015 detail: "fn frobnicate()",
1016 },
1017 CompletionItem {
1018 label: "main",
1019 source_range: 35..39,
1020 delete: 35..39,
1021 insert: "main",
1022 kind: Function,
1023 detail: "fn main()",
1024 },
1025 ]
1026 "###
1027 ); 828 );
1028 assert_debug_snapshot!( 829 check_edit(
1029 do_reference_completion( 830 "foo",
1030 " 831 r#"
1031 //- /lib.rs 832struct Foo;
1032 struct Foo {} 833impl Foo { fn foo(&self){} }
1033 impl Foo { fn new() -> Foo {} } 834fn f(foo: &Foo) { foo.f<|>(); }
1034 fn main() { 835"#,
1035 Foo::ne<|>(); 836 r#"
1036 } 837struct Foo;
1037 " 838impl Foo { fn foo(&self){} }
1038 ), 839fn f(foo: &Foo) { foo.foo(); }
1039 @r###" 840"#,
1040 [
1041 CompletionItem {
1042 label: "new",
1043 source_range: 67..69,
1044 delete: 67..69,
1045 insert: "new",
1046 kind: Function,
1047 detail: "fn new() -> Foo",
1048 },
1049 ]
1050 "###
1051 ); 841 );
1052 } 842 }
1053 843
@@ -1516,54 +1306,4 @@ mod tests {
1516 "### 1306 "###
1517 ); 1307 );
1518 } 1308 }
1519
1520 #[test]
1521 fn no_keyword_autocompletion_on_line_comments() {
1522 assert_debug_snapshot!(
1523 do_completion(
1524 r"
1525 fn test() {
1526 let x = 2; // A comment<|>
1527 }
1528 ",
1529 CompletionKind::Keyword
1530 ),
1531 @r###"
1532 []
1533 "###
1534 );
1535 }
1536
1537 #[test]
1538 fn no_keyword_autocompletion_on_multi_line_comments() {
1539 assert_debug_snapshot!(
1540 do_completion(
1541 r"
1542 /*
1543 Some multi-line comment<|>
1544 */
1545 ",
1546 CompletionKind::Keyword
1547 ),
1548 @r###"
1549 []
1550 "###
1551 );
1552 }
1553
1554 #[test]
1555 fn no_keyword_autocompletion_on_doc_comments() {
1556 assert_debug_snapshot!(
1557 do_completion(
1558 r"
1559 /// Some doc comment
1560 /// let test<|> = 1
1561 ",
1562 CompletionKind::Keyword
1563 ),
1564 @r###"
1565 []
1566 "###
1567 );
1568 }
1569} 1309}
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index 5c01654cc..145d36c98 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -1,7 +1,10 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use hir::Semantics; 3use hir::Semantics;
4use itertools::Itertools;
4use ra_syntax::{AstNode, NodeOrToken, SyntaxElement}; 5use ra_syntax::{AstNode, NodeOrToken, SyntaxElement};
6use stdx::{format_to, trim_indent};
7use test_utils::assert_eq_text;
5 8
6use crate::{ 9use crate::{
7 completion::{completion_item::CompletionKind, CompletionConfig}, 10 completion::{completion_item::CompletionKind, CompletionConfig},
@@ -42,10 +45,41 @@ pub(crate) fn completion_list_with_options(
42 kind_completions.sort_by_key(|c| c.label().to_owned()); 45 kind_completions.sort_by_key(|c| c.label().to_owned());
43 kind_completions 46 kind_completions
44 .into_iter() 47 .into_iter()
45 .map(|it| format!("{} {}\n", it.kind().unwrap().tag(), it.label())) 48 .map(|it| {
49 let mut buf = format!("{} {}", it.kind().unwrap().tag(), it.label());
50 if let Some(detail) = it.detail() {
51 format_to!(buf, " {}", detail);
52 }
53 format_to!(buf, "\n");
54 buf
55 })
46 .collect() 56 .collect()
47} 57}
48 58
59pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
60 check_edit_with_config(what, ra_fixture_before, ra_fixture_after, &CompletionConfig::default())
61}
62
63pub(crate) fn check_edit_with_config(
64 what: &str,
65 ra_fixture_before: &str,
66 ra_fixture_after: &str,
67 config: &CompletionConfig,
68) {
69 let ra_fixture_after = trim_indent(ra_fixture_after);
70 let (analysis, position) = analysis_and_position(ra_fixture_before);
71 let completions: Vec<CompletionItem> =
72 analysis.completions(config, position).unwrap().unwrap().into();
73 let (completion,) = completions
74 .iter()
75 .filter(|it| it.lookup() == what)
76 .collect_tuple()
77 .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
78 let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
79 completion.text_edit().apply(&mut actual);
80 assert_eq_text!(&ra_fixture_after, &actual)
81}
82
49pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) { 83pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
50 let (analysis, pos) = analysis_and_position(code); 84 let (analysis, pos) = analysis_and_position(code);
51 analysis 85 analysis