diff options
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 1675 |
1 files changed, 693 insertions, 982 deletions
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 4fdc2f0bb..9a94ff476 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | //! It also handles scoring (sorting) completions. | ||
2 | 3 | ||
3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; | 4 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; |
4 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
@@ -10,7 +11,7 @@ use crate::{ | |||
10 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, |
11 | CompletionKind, Completions, | 12 | CompletionKind, Completions, |
12 | }, | 13 | }, |
13 | display::{const_label, macro_label, type_label, FunctionSignature}, | 14 | display::{const_label, function_declaration, macro_label, type_label}, |
14 | CompletionScore, RootDatabase, | 15 | CompletionScore, RootDatabase, |
15 | }; | 16 | }; |
16 | 17 | ||
@@ -78,11 +79,10 @@ impl Completions { | |||
78 | return self.add_macro(ctx, Some(local_name), *mac); | 79 | return self.add_macro(ctx, Some(local_name), *mac); |
79 | } | 80 | } |
80 | ScopeDef::Unknown => { | 81 | ScopeDef::Unknown => { |
81 | return self.add(CompletionItem::new( | 82 | return self.add( |
82 | CompletionKind::Reference, | 83 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name) |
83 | ctx.source_range(), | 84 | .kind(CompletionItemKind::UnresolvedReference), |
84 | local_name, | 85 | ); |
85 | )); | ||
86 | } | 86 | } |
87 | }; | 87 | }; |
88 | 88 | ||
@@ -173,6 +173,7 @@ impl Completions { | |||
173 | builder | 173 | builder |
174 | .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket)) | 174 | .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket)) |
175 | .label(format!("{}!{}…{}", name, bra, ket)) | 175 | .label(format!("{}!{}…{}", name, bra, ket)) |
176 | .lookup_by(format!("{}!", name)) | ||
176 | } | 177 | } |
177 | None if needs_bang => builder.insert_text(format!("{}!", name)), | 178 | None if needs_bang => builder.insert_text(format!("{}!", name)), |
178 | _ => { | 179 | _ => { |
@@ -194,7 +195,6 @@ impl Completions { | |||
194 | 195 | ||
195 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); | 196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); |
196 | let ast_node = func.source(ctx.db).value; | 197 | let ast_node = func.source(ctx.db).value; |
197 | let function_signature = FunctionSignature::from(&ast_node); | ||
198 | 198 | ||
199 | let mut builder = | 199 | let mut builder = |
200 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) | 200 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) |
@@ -205,13 +205,14 @@ impl Completions { | |||
205 | }) | 205 | }) |
206 | .set_documentation(func.docs(ctx.db)) | 206 | .set_documentation(func.docs(ctx.db)) |
207 | .set_deprecated(is_deprecated(func, ctx.db)) | 207 | .set_deprecated(is_deprecated(func, ctx.db)) |
208 | .detail(function_signature.to_string()); | 208 | .detail(function_declaration(&ast_node)); |
209 | 209 | ||
210 | let params = function_signature | 210 | let params = ast_node |
211 | .parameter_names | 211 | .param_list() |
212 | .iter() | 212 | .into_iter() |
213 | .skip(if function_signature.has_self_param { 1 } else { 0 }) | 213 | .flat_map(|it| it.params()) |
214 | .map(|name| name.trim_start_matches('_').into()) | 214 | .flat_map(|it| it.pat()) |
215 | .map(|pat| pat.to_string().trim_start_matches('_').into()) | ||
215 | .collect(); | 216 | .collect(); |
216 | 217 | ||
217 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); | 218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); |
@@ -314,6 +315,7 @@ impl Completions { | |||
314 | } | 315 | } |
315 | 316 | ||
316 | if variant_kind == StructKind::Tuple { | 317 | if variant_kind == StructKind::Tuple { |
318 | mark::hit!(inserts_parens_for_tuple_enums); | ||
317 | let params = Params::Anonymous(variant.fields(ctx.db).len()); | 319 | let params = Params::Anonymous(variant.fields(ctx.db).len()); |
318 | res = res.add_call_parens(ctx, qualified_name, params) | 320 | res = res.add_call_parens(ctx, qualified_name, params) |
319 | } | 321 | } |
@@ -327,17 +329,12 @@ pub(crate) fn compute_score( | |||
327 | ty: &Type, | 329 | ty: &Type, |
328 | name: &str, | 330 | name: &str, |
329 | ) -> Option<CompletionScore> { | 331 | ) -> Option<CompletionScore> { |
330 | // FIXME: this should not fall back to string equality. | ||
331 | let ty = &ty.display(ctx.db).to_string(); | ||
332 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { | 332 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { |
333 | mark::hit!(test_struct_field_completion_in_record_lit); | 333 | mark::hit!(record_field_type_match); |
334 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; | 334 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; |
335 | ( | 335 | (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db)) |
336 | struct_field.name(ctx.db).to_string(), | ||
337 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | ||
338 | ) | ||
339 | } else if let Some(active_parameter) = &ctx.active_parameter { | 336 | } else if let Some(active_parameter) = &ctx.active_parameter { |
340 | mark::hit!(test_struct_field_completion_in_func_call); | 337 | mark::hit!(active_param_type_match); |
341 | (active_parameter.name.clone(), active_parameter.ty.clone()) | 338 | (active_parameter.name.clone(), active_parameter.ty.clone()) |
342 | } else { | 339 | } else { |
343 | return None; | 340 | return None; |
@@ -382,13 +379,22 @@ impl Builder { | |||
382 | if !ctx.config.add_call_parenthesis { | 379 | if !ctx.config.add_call_parenthesis { |
383 | return self; | 380 | return self; |
384 | } | 381 | } |
385 | if ctx.use_item_syntax.is_some() || ctx.is_call { | 382 | if ctx.use_item_syntax.is_some() { |
383 | mark::hit!(no_parens_in_use_item); | ||
384 | return self; | ||
385 | } | ||
386 | if ctx.is_pattern_call { | ||
387 | mark::hit!(dont_duplicate_pattern_parens); | ||
388 | return self; | ||
389 | } | ||
390 | if ctx.is_call { | ||
386 | return self; | 391 | return self; |
387 | } | 392 | } |
388 | 393 | ||
389 | // Don't add parentheses if the expected type is some function reference. | 394 | // Don't add parentheses if the expected type is some function reference. |
390 | if let Some(ty) = &ctx.expected_type { | 395 | if let Some(ty) = &ctx.expected_type { |
391 | if ty.is_fn() { | 396 | if ty.is_fn() { |
397 | mark::hit!(no_call_parens_if_fn_ptr_needed); | ||
392 | return self; | 398 | return self; |
393 | } | 399 | } |
394 | } | 400 | } |
@@ -413,7 +419,10 @@ impl Builder { | |||
413 | .sep_by(", "); | 419 | .sep_by(", "); |
414 | format!("{}({})$0", name, function_params_snippet) | 420 | format!("{}({})$0", name, function_params_snippet) |
415 | } | 421 | } |
416 | _ => format!("{}($0)", name), | 422 | _ => { |
423 | mark::hit!(suppress_arg_snippets); | ||
424 | format!("{}($0)", name) | ||
425 | } | ||
417 | }; | 426 | }; |
418 | 427 | ||
419 | (snippet, format!("{}(…)", name)) | 428 | (snippet, format!("{}(…)", name)) |
@@ -456,1064 +465,766 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s | |||
456 | 465 | ||
457 | #[cfg(test)] | 466 | #[cfg(test)] |
458 | mod tests { | 467 | mod tests { |
459 | use insta::assert_debug_snapshot; | 468 | use std::cmp::Reverse; |
469 | |||
470 | use expect::{expect, Expect}; | ||
460 | use test_utils::mark; | 471 | use test_utils::mark; |
461 | 472 | ||
462 | use crate::completion::{ | 473 | use crate::{ |
463 | test_utils::{do_completion, do_completion_with_options}, | 474 | completion::{ |
464 | CompletionConfig, CompletionItem, CompletionKind, | 475 | test_utils::{ |
476 | check_edit, check_edit_with_config, do_completion, get_all_completion_items, | ||
477 | }, | ||
478 | CompletionConfig, CompletionKind, | ||
479 | }, | ||
480 | CompletionScore, | ||
465 | }; | 481 | }; |
466 | 482 | ||
467 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { | 483 | fn check(ra_fixture: &str, expect: Expect) { |
468 | do_completion(ra_fixture, CompletionKind::Reference) | 484 | let actual = do_completion(ra_fixture, CompletionKind::Reference); |
485 | expect.assert_debug_eq(&actual); | ||
469 | } | 486 | } |
470 | 487 | ||
471 | fn do_reference_completion_with_options( | 488 | fn check_scores(ra_fixture: &str, expect: Expect) { |
472 | ra_fixture: &str, | 489 | fn display_score(score: Option<CompletionScore>) -> &'static str { |
473 | options: CompletionConfig, | 490 | match score { |
474 | ) -> Vec<CompletionItem> { | 491 | Some(CompletionScore::TypeMatch) => "[type]", |
475 | do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) | 492 | Some(CompletionScore::TypeAndNameMatch) => "[type+name]", |
493 | None => "[]".into(), | ||
494 | } | ||
495 | } | ||
496 | |||
497 | let mut completions = get_all_completion_items(CompletionConfig::default(), ra_fixture); | ||
498 | completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); | ||
499 | let actual = completions | ||
500 | .into_iter() | ||
501 | .filter(|it| it.completion_kind == CompletionKind::Reference) | ||
502 | .map(|it| { | ||
503 | let tag = it.kind().unwrap().tag(); | ||
504 | let score = display_score(it.score()); | ||
505 | format!("{} {} {}\n", tag, it.label(), score) | ||
506 | }) | ||
507 | .collect::<String>(); | ||
508 | expect.assert_eq(&actual); | ||
476 | } | 509 | } |
477 | 510 | ||
478 | #[test] | 511 | #[test] |
479 | fn enum_detail_includes_names_for_record() { | 512 | fn enum_detail_includes_record_fields() { |
480 | assert_debug_snapshot!( | 513 | check( |
481 | do_reference_completion( | ||
482 | r#" | 514 | r#" |
483 | enum Foo { | 515 | enum Foo { Foo { x: i32, y: i32 } } |
484 | Foo {x: i32, y: i32} | 516 | |
485 | } | 517 | fn main() { Foo::Fo<|> } |
486 | 518 | "#, | |
487 | fn main() { Foo::Fo<|> } | 519 | expect![[r#" |
488 | "#, | 520 | [ |
489 | ), | 521 | CompletionItem { |
490 | @r###" | 522 | label: "Foo", |
491 | [ | 523 | source_range: 54..56, |
492 | CompletionItem { | 524 | delete: 54..56, |
493 | label: "Foo", | 525 | insert: "Foo", |
494 | source_range: 56..58, | 526 | kind: EnumVariant, |
495 | delete: 56..58, | 527 | detail: "{ x: i32, y: i32 }", |
496 | insert: "Foo", | 528 | }, |
497 | kind: EnumVariant, | 529 | ] |
498 | detail: "{ x: i32, y: i32 }", | 530 | "#]], |
499 | }, | ||
500 | ] | ||
501 | "### | ||
502 | ); | 531 | ); |
503 | } | 532 | } |
504 | 533 | ||
505 | #[test] | 534 | #[test] |
506 | fn enum_detail_doesnt_include_names_for_tuple() { | 535 | fn enum_detail_doesnt_include_tuple_fields() { |
507 | assert_debug_snapshot!( | 536 | check( |
508 | do_reference_completion( | ||
509 | r#" | 537 | r#" |
510 | enum Foo { | 538 | enum Foo { Foo (i32, i32) } |
511 | Foo (i32, i32) | 539 | |
512 | } | 540 | fn main() { Foo::Fo<|> } |
513 | 541 | "#, | |
514 | fn main() { Foo::Fo<|> } | 542 | expect![[r#" |
515 | "#, | 543 | [ |
516 | ), | 544 | CompletionItem { |
517 | @r###" | 545 | label: "Foo(…)", |
518 | [ | 546 | source_range: 46..48, |
519 | CompletionItem { | 547 | delete: 46..48, |
520 | label: "Foo(…)", | 548 | insert: "Foo($0)", |
521 | source_range: 50..52, | 549 | kind: EnumVariant, |
522 | delete: 50..52, | 550 | lookup: "Foo", |
523 | insert: "Foo($0)", | 551 | detail: "(i32, i32)", |
524 | kind: EnumVariant, | 552 | trigger_call_info: true, |
525 | lookup: "Foo", | 553 | }, |
526 | detail: "(i32, i32)", | 554 | ] |
527 | trigger_call_info: true, | 555 | "#]], |
528 | }, | ||
529 | ] | ||
530 | "### | ||
531 | ); | 556 | ); |
532 | } | 557 | } |
533 | 558 | ||
534 | #[test] | 559 | #[test] |
535 | fn enum_detail_just_parentheses_for_unit() { | 560 | fn enum_detail_just_parentheses_for_unit() { |
536 | assert_debug_snapshot!( | 561 | check( |
537 | do_reference_completion( | ||
538 | r#" | 562 | r#" |
539 | enum Foo { | 563 | enum Foo { Foo } |
540 | Foo | 564 | |
541 | } | 565 | fn main() { Foo::Fo<|> } |
542 | 566 | "#, | |
543 | fn main() { Foo::Fo<|> } | 567 | expect![[r#" |
544 | "#, | 568 | [ |
545 | ), | 569 | CompletionItem { |
546 | @r###" | 570 | label: "Foo", |
547 | [ | 571 | source_range: 35..37, |
548 | CompletionItem { | 572 | delete: 35..37, |
549 | label: "Foo", | 573 | insert: "Foo", |
550 | source_range: 39..41, | 574 | kind: EnumVariant, |
551 | delete: 39..41, | 575 | detail: "()", |
552 | insert: "Foo", | 576 | }, |
553 | kind: EnumVariant, | 577 | ] |
554 | detail: "()", | 578 | "#]], |
555 | }, | ||
556 | ] | ||
557 | "### | ||
558 | ); | 579 | ); |
559 | } | 580 | } |
560 | 581 | ||
561 | #[test] | 582 | #[test] |
562 | fn sets_deprecated_flag_in_completion_items() { | 583 | fn sets_deprecated_flag_in_completion_items() { |
563 | assert_debug_snapshot!( | 584 | check( |
564 | do_reference_completion( | 585 | r#" |
565 | r#" | 586 | #[deprecated] |
566 | #[deprecated] | 587 | fn something_deprecated() {} |
567 | fn something_deprecated() {} | 588 | #[deprecated(since = "1.0.0")] |
568 | 589 | fn something_else_deprecated() {} | |
569 | #[deprecated(since = "1.0.0")] | 590 | |
570 | fn something_else_deprecated() {} | 591 | fn main() { som<|> } |
571 | 592 | "#, | |
572 | fn main() { som<|> } | 593 | expect![[r#" |
573 | "#, | 594 | [ |
574 | ), | 595 | CompletionItem { |
575 | @r###" | 596 | label: "main()", |
576 | [ | 597 | source_range: 121..124, |
577 | CompletionItem { | 598 | delete: 121..124, |
578 | label: "main()", | 599 | insert: "main()$0", |
579 | source_range: 122..125, | 600 | kind: Function, |
580 | delete: 122..125, | 601 | lookup: "main", |
581 | insert: "main()$0", | 602 | detail: "fn main()", |
582 | kind: Function, | 603 | }, |
583 | lookup: "main", | 604 | CompletionItem { |
584 | detail: "fn main()", | 605 | label: "something_deprecated()", |
585 | }, | 606 | source_range: 121..124, |
586 | CompletionItem { | 607 | delete: 121..124, |
587 | label: "something_deprecated()", | 608 | insert: "something_deprecated()$0", |
588 | source_range: 122..125, | 609 | kind: Function, |
589 | delete: 122..125, | 610 | lookup: "something_deprecated", |
590 | insert: "something_deprecated()$0", | 611 | detail: "fn something_deprecated()", |
591 | kind: Function, | 612 | deprecated: true, |
592 | lookup: "something_deprecated", | 613 | }, |
593 | detail: "fn something_deprecated()", | 614 | CompletionItem { |
594 | deprecated: true, | 615 | label: "something_else_deprecated()", |
595 | }, | 616 | source_range: 121..124, |
596 | CompletionItem { | 617 | delete: 121..124, |
597 | label: "something_else_deprecated()", | 618 | insert: "something_else_deprecated()$0", |
598 | source_range: 122..125, | 619 | kind: Function, |
599 | delete: 122..125, | 620 | lookup: "something_else_deprecated", |
600 | insert: "something_else_deprecated()$0", | 621 | detail: "fn something_else_deprecated()", |
601 | kind: Function, | 622 | deprecated: true, |
602 | lookup: "something_else_deprecated", | 623 | }, |
603 | detail: "fn something_else_deprecated()", | 624 | ] |
604 | deprecated: true, | 625 | "#]], |
605 | }, | 626 | ); |
606 | ] | 627 | |
607 | "### | 628 | check( |
629 | r#" | ||
630 | struct A { #[deprecated] the_field: u32 } | ||
631 | fn foo() { A { the<|> } } | ||
632 | "#, | ||
633 | expect![[r#" | ||
634 | [ | ||
635 | CompletionItem { | ||
636 | label: "the_field", | ||
637 | source_range: 57..60, | ||
638 | delete: 57..60, | ||
639 | insert: "the_field", | ||
640 | kind: Field, | ||
641 | detail: "u32", | ||
642 | deprecated: true, | ||
643 | }, | ||
644 | ] | ||
645 | "#]], | ||
646 | ); | ||
647 | } | ||
648 | |||
649 | #[test] | ||
650 | fn renders_docs() { | ||
651 | check( | ||
652 | r#" | ||
653 | struct S { | ||
654 | /// Field docs | ||
655 | foo: | ||
656 | } | ||
657 | impl S { | ||
658 | /// Method docs | ||
659 | fn bar(self) { self.<|> } | ||
660 | }"#, | ||
661 | expect![[r#" | ||
662 | [ | ||
663 | CompletionItem { | ||
664 | label: "bar()", | ||
665 | source_range: 94..94, | ||
666 | delete: 94..94, | ||
667 | insert: "bar()$0", | ||
668 | kind: Method, | ||
669 | lookup: "bar", | ||
670 | detail: "fn bar(self)", | ||
671 | documentation: Documentation( | ||
672 | "Method docs", | ||
673 | ), | ||
674 | }, | ||
675 | CompletionItem { | ||
676 | label: "foo", | ||
677 | source_range: 94..94, | ||
678 | delete: 94..94, | ||
679 | insert: "foo", | ||
680 | kind: Field, | ||
681 | detail: "{unknown}", | ||
682 | documentation: Documentation( | ||
683 | "Field docs", | ||
684 | ), | ||
685 | }, | ||
686 | ] | ||
687 | "#]], | ||
608 | ); | 688 | ); |
689 | |||
690 | check( | ||
691 | r#" | ||
692 | use self::my<|>; | ||
693 | |||
694 | /// mod docs | ||
695 | mod my { } | ||
696 | |||
697 | /// enum docs | ||
698 | enum E { | ||
699 | /// variant docs | ||
700 | V | ||
701 | } | ||
702 | use self::E::*; | ||
703 | "#, | ||
704 | expect![[r#" | ||
705 | [ | ||
706 | CompletionItem { | ||
707 | label: "E", | ||
708 | source_range: 10..12, | ||
709 | delete: 10..12, | ||
710 | insert: "E", | ||
711 | kind: Enum, | ||
712 | documentation: Documentation( | ||
713 | "enum docs", | ||
714 | ), | ||
715 | }, | ||
716 | CompletionItem { | ||
717 | label: "V", | ||
718 | source_range: 10..12, | ||
719 | delete: 10..12, | ||
720 | insert: "V", | ||
721 | kind: EnumVariant, | ||
722 | detail: "()", | ||
723 | documentation: Documentation( | ||
724 | "variant docs", | ||
725 | ), | ||
726 | }, | ||
727 | CompletionItem { | ||
728 | label: "my", | ||
729 | source_range: 10..12, | ||
730 | delete: 10..12, | ||
731 | insert: "my", | ||
732 | kind: Module, | ||
733 | documentation: Documentation( | ||
734 | "mod docs", | ||
735 | ), | ||
736 | }, | ||
737 | ] | ||
738 | "#]], | ||
739 | ) | ||
740 | } | ||
741 | |||
742 | #[test] | ||
743 | fn dont_render_attrs() { | ||
744 | check( | ||
745 | r#" | ||
746 | struct S; | ||
747 | impl S { | ||
748 | #[inline] | ||
749 | fn the_method(&self) { } | ||
750 | } | ||
751 | fn foo(s: S) { s.<|> } | ||
752 | "#, | ||
753 | expect![[r#" | ||
754 | [ | ||
755 | CompletionItem { | ||
756 | label: "the_method()", | ||
757 | source_range: 81..81, | ||
758 | delete: 81..81, | ||
759 | insert: "the_method()$0", | ||
760 | kind: Method, | ||
761 | lookup: "the_method", | ||
762 | detail: "fn the_method(&self)", | ||
763 | }, | ||
764 | ] | ||
765 | "#]], | ||
766 | ) | ||
609 | } | 767 | } |
610 | 768 | ||
611 | #[test] | 769 | #[test] |
612 | fn inserts_parens_for_function_calls() { | 770 | fn inserts_parens_for_function_calls() { |
613 | mark::check!(inserts_parens_for_function_calls); | 771 | mark::check!(inserts_parens_for_function_calls); |
614 | assert_debug_snapshot!( | 772 | check_edit( |
615 | do_reference_completion( | 773 | "no_args", |
616 | r" | 774 | r#" |
617 | fn no_args() {} | 775 | fn no_args() {} |
618 | fn main() { no_<|> } | 776 | fn main() { no_<|> } |
619 | " | 777 | "#, |
620 | ), | 778 | r#" |
621 | @r###" | 779 | fn no_args() {} |
622 | [ | 780 | fn main() { no_args()$0 } |
623 | CompletionItem { | 781 | "#, |
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 | [ | ||
653 | CompletionItem { | ||
654 | label: "main()", | ||
655 | source_range: 47..52, | ||
656 | delete: 47..52, | ||
657 | insert: "main()$0", | ||
658 | kind: Function, | ||
659 | lookup: "main", | ||
660 | detail: "fn main()", | ||
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 | }, | ||
672 | ] | ||
673 | "### | ||
674 | ); | 782 | ); |
675 | assert_debug_snapshot!( | 783 | |
676 | do_reference_completion( | 784 | check_edit( |
677 | r" | 785 | "with_args", |
678 | fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String) {} | 786 | r#" |
679 | fn main() { with_<|> } | 787 | fn with_args(x: i32, y: String) {} |
680 | " | 788 | fn main() { with_<|> } |
681 | ), | 789 | "#, |
682 | @r###" | 790 | r#" |
683 | [ | 791 | fn with_args(x: i32, y: String) {} |
684 | CompletionItem { | 792 | fn main() { with_args(${1:x}, ${2:y})$0 } |
685 | label: "main()", | 793 | "#, |
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 | ); | 794 | ); |
706 | assert_debug_snapshot!( | 795 | |
707 | do_reference_completion( | 796 | check_edit( |
708 | r" | 797 | "foo", |
709 | struct S {} | 798 | r#" |
710 | impl S { | 799 | struct S; |
711 | fn foo(&self) {} | 800 | impl S { |
712 | } | 801 | fn foo(&self) {} |
713 | fn bar(s: &S) { | 802 | } |
714 | s.f<|> | 803 | fn bar(s: &S) { s.f<|> } |
715 | } | 804 | "#, |
716 | " | 805 | r#" |
717 | ), | 806 | struct S; |
718 | @r###" | 807 | impl S { |
719 | [ | 808 | fn foo(&self) {} |
720 | CompletionItem { | 809 | } |
721 | label: "foo()", | 810 | fn bar(s: &S) { s.foo()$0 } |
722 | source_range: 66..67, | 811 | "#, |
723 | delete: 66..67, | ||
724 | insert: "foo()$0", | ||
725 | kind: Method, | ||
726 | lookup: "foo", | ||
727 | detail: "fn foo(&self)", | ||
728 | }, | ||
729 | ] | ||
730 | "### | ||
731 | ); | 812 | ); |
732 | assert_debug_snapshot!( | 813 | |
733 | do_reference_completion( | 814 | check_edit( |
734 | r" | 815 | "foo", |
735 | struct S {} | 816 | r#" |
736 | impl S { | 817 | struct S {} |
737 | fn foo_ignored_args(&self, _a: bool, b: i32) {} | 818 | impl S { |
738 | } | 819 | fn foo(&self, x: i32) {} |
739 | fn bar(s: &S) { | 820 | } |
740 | s.f<|> | 821 | fn bar(s: &S) { |
741 | } | 822 | s.f<|> |
742 | " | 823 | } |
743 | ), | 824 | "#, |
744 | @r###" | 825 | r#" |
745 | [ | 826 | struct S {} |
746 | CompletionItem { | 827 | impl S { |
747 | label: "foo_ignored_args(…)", | 828 | fn foo(&self, x: i32) {} |
748 | source_range: 97..98, | 829 | } |
749 | delete: 97..98, | 830 | fn bar(s: &S) { |
750 | insert: "foo_ignored_args(${1:a}, ${2:b})$0", | 831 | s.foo(${1:x})$0 |
751 | kind: Method, | 832 | } |
752 | lookup: "foo_ignored_args", | 833 | "#, |
753 | detail: "fn foo_ignored_args(&self, _a: bool, b: i32)", | ||
754 | trigger_call_info: true, | ||
755 | }, | ||
756 | ] | ||
757 | "### | ||
758 | ); | 834 | ); |
759 | } | 835 | } |
760 | 836 | ||
761 | #[test] | 837 | #[test] |
762 | fn inserts_parens_for_tuple_enums() { | 838 | fn suppress_arg_snippets() { |
763 | assert_debug_snapshot!( | 839 | mark::check!(suppress_arg_snippets); |
764 | do_reference_completion( | 840 | check_edit_with_config( |
765 | r" | 841 | CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() }, |
766 | enum Option<T> { Some(T), None } | 842 | "with_args", |
767 | use Option::*; | 843 | r#" |
768 | fn main() -> Option<i32> { | 844 | fn with_args(x: i32, y: String) {} |
769 | Som<|> | 845 | fn main() { with_<|> } |
770 | } | 846 | "#, |
771 | " | 847 | r#" |
772 | ), | 848 | fn with_args(x: i32, y: String) {} |
773 | @r###" | 849 | fn main() { with_args($0) } |
774 | [ | 850 | "#, |
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 | ); | 851 | ); |
854 | } | 852 | } |
855 | 853 | ||
856 | #[test] | 854 | #[test] |
857 | fn no_call_parens_if_fn_ptr_needed() { | 855 | fn strips_underscores_from_args() { |
858 | assert_debug_snapshot!( | 856 | check_edit( |
859 | do_reference_completion( | 857 | "foo", |
860 | r" | 858 | r#" |
861 | fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8) {} | 859 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} |
862 | 860 | fn main() { f<|> } | |
863 | struct ManualVtable { | 861 | "#, |
864 | method: fn(u8, u8, u8, u8, u8), | 862 | r#" |
865 | } | 863 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} |
864 | fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } | ||
865 | "#, | ||
866 | ); | ||
867 | } | ||
866 | 868 | ||
867 | fn main() -> ManualVtable { | 869 | #[test] |
868 | ManualVtable { | 870 | fn inserts_parens_for_tuple_enums() { |
869 | method: some<|> | 871 | mark::check!(inserts_parens_for_tuple_enums); |
870 | } | 872 | check_edit( |
871 | } | 873 | "Some", |
872 | " | 874 | r#" |
873 | ), | 875 | enum Option<T> { Some(T), None } |
874 | @r###" | 876 | use Option::*; |
875 | [ | 877 | fn main() -> Option<i32> { |
876 | CompletionItem { | 878 | Som<|> |
877 | label: "ManualVtable", | 879 | } |
878 | source_range: 182..186, | 880 | "#, |
879 | delete: 182..186, | 881 | r#" |
880 | insert: "ManualVtable", | 882 | enum Option<T> { Some(T), None } |
881 | kind: Struct, | 883 | use Option::*; |
882 | }, | 884 | fn main() -> Option<i32> { |
883 | CompletionItem { | 885 | Some($0) |
884 | label: "main", | 886 | } |
885 | source_range: 182..186, | 887 | "#, |
886 | delete: 182..186, | 888 | ); |
887 | insert: "main", | 889 | check_edit( |
888 | kind: Function, | 890 | "Some", |
889 | detail: "fn main() -> ManualVtable", | 891 | r#" |
890 | }, | 892 | enum Option<T> { Some(T), None } |
891 | CompletionItem { | 893 | use Option::*; |
892 | label: "somefn", | 894 | fn main(value: Option<i32>) { |
893 | source_range: 182..186, | 895 | match value { |
894 | delete: 182..186, | 896 | Som<|> |
895 | insert: "somefn", | 897 | } |
896 | kind: Function, | 898 | } |
897 | detail: "fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8)", | 899 | "#, |
898 | }, | 900 | r#" |
899 | ] | 901 | enum Option<T> { Some(T), None } |
900 | "### | 902 | use Option::*; |
903 | fn main(value: Option<i32>) { | ||
904 | match value { | ||
905 | Some($0) | ||
906 | } | ||
907 | } | ||
908 | "#, | ||
901 | ); | 909 | ); |
902 | } | 910 | } |
903 | 911 | ||
904 | #[test] | 912 | #[test] |
905 | fn arg_snippets_for_method_call() { | 913 | fn dont_duplicate_pattern_parens() { |
906 | assert_debug_snapshot!( | 914 | mark::check!(dont_duplicate_pattern_parens); |
907 | do_reference_completion( | 915 | check_edit( |
908 | r" | 916 | "Var", |
909 | struct S {} | 917 | r#" |
910 | impl S { | 918 | enum E { Var(i32) } |
911 | fn foo(&self, x: i32) {} | 919 | fn main() { |
912 | } | 920 | match E::Var(92) { |
913 | fn bar(s: &S) { | 921 | E::<|>(92) => (), |
914 | s.f<|> | 922 | } |
915 | } | 923 | } |
916 | " | 924 | "#, |
917 | ), | 925 | r#" |
918 | @r###" | 926 | enum E { Var(i32) } |
919 | [ | 927 | fn main() { |
920 | CompletionItem { | 928 | match E::Var(92) { |
921 | label: "foo(…)", | 929 | E::Var(92) => (), |
922 | source_range: 74..75, | 930 | } |
923 | delete: 74..75, | 931 | } |
924 | insert: "foo(${1:x})$0", | 932 | "#, |
925 | kind: Method, | 933 | ); |
926 | lookup: "foo", | ||
927 | detail: "fn foo(&self, x: i32)", | ||
928 | trigger_call_info: true, | ||
929 | }, | ||
930 | ] | ||
931 | "### | ||
932 | ) | ||
933 | } | 934 | } |
934 | 935 | ||
935 | #[test] | 936 | #[test] |
936 | fn no_arg_snippets_for_method_call() { | 937 | fn no_call_parens_if_fn_ptr_needed() { |
937 | assert_debug_snapshot!( | 938 | mark::check!(no_call_parens_if_fn_ptr_needed); |
938 | do_reference_completion_with_options( | 939 | check_edit( |
939 | r" | 940 | "foo", |
940 | struct S {} | 941 | r#" |
941 | impl S { | 942 | fn foo(foo: u8, bar: u8) {} |
942 | fn foo(&self, x: i32) {} | 943 | struct ManualVtable { f: fn(u8, u8) } |
943 | } | 944 | |
944 | fn bar(s: &S) { | 945 | fn main() -> ManualVtable { |
945 | s.f<|> | 946 | ManualVtable { f: f<|> } |
946 | } | 947 | } |
947 | ", | 948 | "#, |
948 | CompletionConfig { | 949 | r#" |
949 | add_call_argument_snippets: false, | 950 | fn foo(foo: u8, bar: u8) {} |
950 | .. Default::default() | 951 | struct ManualVtable { f: fn(u8, u8) } |
951 | } | 952 | |
952 | ), | 953 | fn main() -> ManualVtable { |
953 | @r###" | 954 | ManualVtable { f: foo } |
954 | [ | 955 | } |
955 | CompletionItem { | 956 | "#, |
956 | label: "foo(…)", | 957 | ); |
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 | } | 958 | } |
969 | 959 | ||
970 | #[test] | 960 | #[test] |
971 | fn dont_render_function_parens_in_use_item() { | 961 | fn no_parens_in_use_item() { |
972 | assert_debug_snapshot!( | 962 | mark::check!(no_parens_in_use_item); |
973 | do_reference_completion( | 963 | check_edit( |
974 | " | 964 | "foo", |
975 | //- /lib.rs | 965 | r#" |
976 | mod m { pub fn foo() {} } | 966 | mod m { pub fn foo() {} } |
977 | use crate::m::f<|>; | 967 | use crate::m::f<|>; |
978 | " | 968 | "#, |
979 | ), | 969 | r#" |
980 | @r###" | 970 | mod m { pub fn foo() {} } |
981 | [ | 971 | use crate::m::foo; |
982 | CompletionItem { | 972 | "#, |
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 | ); | 973 | ); |
993 | } | 974 | } |
994 | 975 | ||
995 | #[test] | 976 | #[test] |
996 | fn dont_render_function_parens_if_already_call() { | 977 | fn no_parens_in_call() { |
997 | assert_debug_snapshot!( | 978 | check_edit( |
998 | do_reference_completion( | 979 | "foo", |
999 | " | 980 | r#" |
1000 | //- /lib.rs | 981 | fn foo(x: i32) {} |
1001 | fn frobnicate() {} | 982 | fn main() { f<|>(); } |
1002 | fn main() { | 983 | "#, |
1003 | frob<|>(); | 984 | r#" |
1004 | } | 985 | fn foo(x: i32) {} |
1005 | " | 986 | fn main() { foo(); } |
1006 | ), | 987 | "#, |
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 | ); | 988 | ); |
1028 | assert_debug_snapshot!( | 989 | check_edit( |
1029 | do_reference_completion( | 990 | "foo", |
1030 | " | 991 | r#" |
1031 | //- /lib.rs | 992 | struct Foo; |
1032 | struct Foo {} | 993 | impl Foo { fn foo(&self){} } |
1033 | impl Foo { fn new() -> Foo {} } | 994 | fn f(foo: &Foo) { foo.f<|>(); } |
1034 | fn main() { | 995 | "#, |
1035 | Foo::ne<|>(); | 996 | r#" |
1036 | } | 997 | struct Foo; |
1037 | " | 998 | impl Foo { fn foo(&self){} } |
1038 | ), | 999 | fn f(foo: &Foo) { foo.foo(); } |
1039 | @r###" | 1000 | "#, |
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 | ); | 1001 | ); |
1052 | } | 1002 | } |
1053 | 1003 | ||
1054 | #[test] | 1004 | #[test] |
1055 | fn inserts_angle_brackets_for_generics() { | 1005 | fn inserts_angle_brackets_for_generics() { |
1056 | mark::check!(inserts_angle_brackets_for_generics); | 1006 | mark::check!(inserts_angle_brackets_for_generics); |
1057 | assert_debug_snapshot!( | 1007 | check_edit( |
1058 | do_reference_completion( | 1008 | "Vec", |
1059 | r" | 1009 | r#" |
1060 | struct Vec<T> {} | 1010 | struct Vec<T> {} |
1061 | fn foo(xs: Ve<|>) | 1011 | fn foo(xs: Ve<|>) |
1062 | " | 1012 | "#, |
1063 | ), | 1013 | r#" |
1064 | @r###" | 1014 | struct Vec<T> {} |
1065 | [ | 1015 | fn foo(xs: Vec<$0>) |
1066 | CompletionItem { | 1016 | "#, |
1067 | label: "Vec<…>", | ||
1068 | source_range: 28..30, | ||
1069 | delete: 28..30, | ||
1070 | insert: "Vec<$0>", | ||
1071 | kind: Struct, | ||
1072 | lookup: "Vec", | ||
1073 | }, | ||
1074 | CompletionItem { | ||
1075 | label: "foo(…)", | ||
1076 | source_range: 28..30, | ||
1077 | delete: 28..30, | ||
1078 | insert: "foo(${1:xs})$0", | ||
1079 | kind: Function, | ||
1080 | lookup: "foo", | ||
1081 | detail: "fn foo(xs: Ve)", | ||
1082 | trigger_call_info: true, | ||
1083 | }, | ||
1084 | ] | ||
1085 | "### | ||
1086 | ); | 1017 | ); |
1087 | assert_debug_snapshot!( | 1018 | check_edit( |
1088 | do_reference_completion( | 1019 | "Vec", |
1089 | r" | 1020 | r#" |
1090 | type Vec<T> = (T,); | 1021 | type Vec<T> = (T,); |
1091 | fn foo(xs: Ve<|>) | 1022 | fn foo(xs: Ve<|>) |
1092 | " | 1023 | "#, |
1093 | ), | 1024 | r#" |
1094 | @r###" | 1025 | type Vec<T> = (T,); |
1095 | [ | 1026 | fn foo(xs: Vec<$0>) |
1096 | CompletionItem { | 1027 | "#, |
1097 | label: "Vec<…>", | ||
1098 | source_range: 31..33, | ||
1099 | delete: 31..33, | ||
1100 | insert: "Vec<$0>", | ||
1101 | kind: TypeAlias, | ||
1102 | lookup: "Vec", | ||
1103 | }, | ||
1104 | CompletionItem { | ||
1105 | label: "foo(…)", | ||
1106 | source_range: 31..33, | ||
1107 | delete: 31..33, | ||
1108 | insert: "foo(${1:xs})$0", | ||
1109 | kind: Function, | ||
1110 | lookup: "foo", | ||
1111 | detail: "fn foo(xs: Ve)", | ||
1112 | trigger_call_info: true, | ||
1113 | }, | ||
1114 | ] | ||
1115 | "### | ||
1116 | ); | 1028 | ); |
1117 | assert_debug_snapshot!( | 1029 | check_edit( |
1118 | do_reference_completion( | 1030 | "Vec", |
1119 | r" | 1031 | r#" |
1120 | struct Vec<T = i128> {} | 1032 | struct Vec<T = i128> {} |
1121 | fn foo(xs: Ve<|>) | 1033 | fn foo(xs: Ve<|>) |
1122 | " | 1034 | "#, |
1123 | ), | 1035 | r#" |
1124 | @r###" | 1036 | struct Vec<T = i128> {} |
1125 | [ | 1037 | fn foo(xs: Vec) |
1126 | CompletionItem { | 1038 | "#, |
1127 | label: "Vec", | ||
1128 | source_range: 35..37, | ||
1129 | delete: 35..37, | ||
1130 | insert: "Vec", | ||
1131 | kind: Struct, | ||
1132 | }, | ||
1133 | CompletionItem { | ||
1134 | label: "foo(…)", | ||
1135 | source_range: 35..37, | ||
1136 | delete: 35..37, | ||
1137 | insert: "foo(${1:xs})$0", | ||
1138 | kind: Function, | ||
1139 | lookup: "foo", | ||
1140 | detail: "fn foo(xs: Ve)", | ||
1141 | trigger_call_info: true, | ||
1142 | }, | ||
1143 | ] | ||
1144 | "### | ||
1145 | ); | 1039 | ); |
1146 | assert_debug_snapshot!( | 1040 | check_edit( |
1147 | do_reference_completion( | 1041 | "Vec", |
1148 | r" | 1042 | r#" |
1149 | struct Vec<T> {} | 1043 | struct Vec<T> {} |
1150 | fn foo(xs: Ve<|><i128>) | 1044 | fn foo(xs: Ve<|><i128>) |
1151 | " | 1045 | "#, |
1152 | ), | 1046 | r#" |
1153 | @r###" | 1047 | struct Vec<T> {} |
1154 | [ | 1048 | fn foo(xs: Vec<i128>) |
1155 | CompletionItem { | 1049 | "#, |
1156 | label: "Vec", | ||
1157 | source_range: 28..30, | ||
1158 | delete: 28..30, | ||
1159 | insert: "Vec", | ||
1160 | kind: Struct, | ||
1161 | }, | ||
1162 | CompletionItem { | ||
1163 | label: "foo(…)", | ||
1164 | source_range: 28..30, | ||
1165 | delete: 28..30, | ||
1166 | insert: "foo(${1:xs})$0", | ||
1167 | kind: Function, | ||
1168 | lookup: "foo", | ||
1169 | detail: "fn foo(xs: Ve<i128>)", | ||
1170 | trigger_call_info: true, | ||
1171 | }, | ||
1172 | ] | ||
1173 | "### | ||
1174 | ); | 1050 | ); |
1175 | } | 1051 | } |
1176 | 1052 | ||
1177 | #[test] | 1053 | #[test] |
1178 | fn dont_insert_macro_call_parens_unncessary() { | 1054 | fn dont_insert_macro_call_parens_unncessary() { |
1179 | mark::check!(dont_insert_macro_call_parens_unncessary); | 1055 | mark::check!(dont_insert_macro_call_parens_unncessary); |
1180 | assert_debug_snapshot!( | 1056 | check_edit( |
1181 | do_reference_completion( | 1057 | "frobnicate!", |
1182 | r" | 1058 | r#" |
1183 | //- /main.rs | 1059 | //- /main.rs |
1184 | use foo::<|>; | 1060 | use foo::<|>; |
1185 | 1061 | //- /foo/lib.rs | |
1186 | //- /foo/lib.rs | 1062 | #[macro_export] |
1187 | #[macro_export] | 1063 | macro_rules frobnicate { () => () } |
1188 | macro_rules frobnicate { | 1064 | "#, |
1189 | () => () | 1065 | r#" |
1190 | } | 1066 | use foo::frobnicate; |
1191 | " | 1067 | "#, |
1192 | ), | ||
1193 | @r###" | ||
1194 | [ | ||
1195 | CompletionItem { | ||
1196 | label: "frobnicate!", | ||
1197 | source_range: 9..9, | ||
1198 | delete: 9..9, | ||
1199 | insert: "frobnicate", | ||
1200 | kind: Macro, | ||
1201 | detail: "#[macro_export]\nmacro_rules! frobnicate", | ||
1202 | }, | ||
1203 | ] | ||
1204 | "### | ||
1205 | ); | 1068 | ); |
1206 | 1069 | ||
1207 | assert_debug_snapshot!( | 1070 | check_edit( |
1208 | do_reference_completion( | 1071 | "frobnicate!", |
1209 | r" | 1072 | r#" |
1210 | //- /main.rs | 1073 | macro_rules frobnicate { () => () } |
1211 | macro_rules frobnicate { | 1074 | fn main() { frob<|>!(); } |
1212 | () => () | 1075 | "#, |
1213 | } | 1076 | r#" |
1214 | fn main() { | 1077 | macro_rules frobnicate { () => () } |
1215 | frob<|>!(); | 1078 | fn main() { frobnicate!(); } |
1216 | } | 1079 | "#, |
1217 | " | ||
1218 | ), | ||
1219 | @r###" | ||
1220 | [ | ||
1221 | CompletionItem { | ||
1222 | label: "frobnicate!", | ||
1223 | source_range: 56..60, | ||
1224 | delete: 56..60, | ||
1225 | insert: "frobnicate", | ||
1226 | kind: Macro, | ||
1227 | detail: "macro_rules! frobnicate", | ||
1228 | }, | ||
1229 | CompletionItem { | ||
1230 | label: "main()", | ||
1231 | source_range: 56..60, | ||
1232 | delete: 56..60, | ||
1233 | insert: "main()$0", | ||
1234 | kind: Function, | ||
1235 | lookup: "main", | ||
1236 | detail: "fn main()", | ||
1237 | }, | ||
1238 | ] | ||
1239 | "### | ||
1240 | ); | 1080 | ); |
1241 | } | 1081 | } |
1242 | 1082 | ||
1243 | #[test] | 1083 | #[test] |
1244 | fn test_struct_field_completion_in_func_call() { | 1084 | fn active_param_score() { |
1245 | mark::check!(test_struct_field_completion_in_func_call); | 1085 | mark::check!(active_param_type_match); |
1246 | assert_debug_snapshot!( | 1086 | check_scores( |
1247 | do_reference_completion( | 1087 | r#" |
1248 | r" | 1088 | struct S { foo: i64, bar: u32, baz: u32 } |
1249 | struct A { another_field: i64, the_field: u32, my_string: String } | 1089 | fn test(bar: u32) { } |
1250 | fn test(my_param: u32) -> u32 { my_param } | 1090 | fn foo(s: S) { test(s.<|>) } |
1251 | fn foo(a: A) { | 1091 | "#, |
1252 | test(a.<|>) | 1092 | expect![[r#" |
1253 | } | 1093 | fd bar [type+name] |
1254 | ", | 1094 | fd baz [type] |
1255 | ), | 1095 | fd foo [] |
1256 | @r###" | 1096 | "#]], |
1257 | [ | ||
1258 | CompletionItem { | ||
1259 | label: "another_field", | ||
1260 | source_range: 136..136, | ||
1261 | delete: 136..136, | ||
1262 | insert: "another_field", | ||
1263 | kind: Field, | ||
1264 | detail: "i64", | ||
1265 | }, | ||
1266 | CompletionItem { | ||
1267 | label: "my_string", | ||
1268 | source_range: 136..136, | ||
1269 | delete: 136..136, | ||
1270 | insert: "my_string", | ||
1271 | kind: Field, | ||
1272 | detail: "{unknown}", | ||
1273 | }, | ||
1274 | CompletionItem { | ||
1275 | label: "the_field", | ||
1276 | source_range: 136..136, | ||
1277 | delete: 136..136, | ||
1278 | insert: "the_field", | ||
1279 | kind: Field, | ||
1280 | detail: "u32", | ||
1281 | score: TypeMatch, | ||
1282 | }, | ||
1283 | ] | ||
1284 | "### | ||
1285 | ); | 1097 | ); |
1286 | } | 1098 | } |
1287 | 1099 | ||
1288 | #[test] | 1100 | #[test] |
1289 | fn test_struct_field_completion_in_func_call_with_type_and_name() { | 1101 | fn record_field_scores() { |
1290 | assert_debug_snapshot!( | 1102 | mark::check!(record_field_type_match); |
1291 | do_reference_completion( | 1103 | check_scores( |
1292 | r" | 1104 | r#" |
1293 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1105 | struct A { foo: i64, bar: u32, baz: u32 } |
1294 | fn test(the_field: u32) -> u32 { the_field } | 1106 | struct B { x: (), y: f32, bar: u32 } |
1295 | fn foo(a: A) { | 1107 | fn foo(a: A) { B { bar: a.<|> }; } |
1296 | test(a.<|>) | 1108 | "#, |
1297 | } | 1109 | expect![[r#" |
1298 | ", | 1110 | fd bar [type+name] |
1299 | ), | 1111 | fd baz [type] |
1300 | @r###" | 1112 | fd foo [] |
1301 | [ | 1113 | "#]], |
1302 | CompletionItem { | 1114 | ) |
1303 | label: "another_field", | ||
1304 | source_range: 143..143, | ||
1305 | delete: 143..143, | ||
1306 | insert: "another_field", | ||
1307 | kind: Field, | ||
1308 | detail: "i64", | ||
1309 | }, | ||
1310 | CompletionItem { | ||
1311 | label: "another_good_type", | ||
1312 | source_range: 143..143, | ||
1313 | delete: 143..143, | ||
1314 | insert: "another_good_type", | ||
1315 | kind: Field, | ||
1316 | detail: "u32", | ||
1317 | score: TypeMatch, | ||
1318 | }, | ||
1319 | CompletionItem { | ||
1320 | label: "the_field", | ||
1321 | source_range: 143..143, | ||
1322 | delete: 143..143, | ||
1323 | insert: "the_field", | ||
1324 | kind: Field, | ||
1325 | detail: "u32", | ||
1326 | score: TypeAndNameMatch, | ||
1327 | }, | ||
1328 | ] | ||
1329 | "### | ||
1330 | ); | ||
1331 | } | 1115 | } |
1332 | 1116 | ||
1333 | #[test] | 1117 | #[test] |
1334 | fn test_struct_field_completion_in_record_lit() { | 1118 | fn record_field_and_call_scores() { |
1335 | mark::check!(test_struct_field_completion_in_record_lit); | 1119 | check_scores( |
1336 | assert_debug_snapshot!( | 1120 | r#" |
1337 | do_reference_completion( | 1121 | struct A { foo: i64, bar: u32, baz: u32 } |
1338 | r" | 1122 | struct B { x: (), y: f32, bar: u32 } |
1339 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1123 | fn f(foo: i64) { } |
1340 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | 1124 | fn foo(a: A) { B { bar: f(a.<|>) }; } |
1341 | fn foo(a: A) { | 1125 | "#, |
1342 | let b = B { | 1126 | expect![[r#" |
1343 | the_field: a.<|> | 1127 | fd foo [type+name] |
1344 | }; | 1128 | fd bar [] |
1345 | } | 1129 | fd baz [] |
1346 | ", | 1130 | "#]], |
1347 | ), | 1131 | ); |
1348 | @r###" | 1132 | check_scores( |
1349 | [ | 1133 | r#" |
1350 | CompletionItem { | 1134 | struct A { foo: i64, bar: u32, baz: u32 } |
1351 | label: "another_field", | 1135 | struct B { x: (), y: f32, bar: u32 } |
1352 | source_range: 189..189, | 1136 | fn f(foo: i64) { } |
1353 | delete: 189..189, | 1137 | fn foo(a: A) { f(B { bar: a.<|> }); } |
1354 | insert: "another_field", | 1138 | "#, |
1355 | kind: Field, | 1139 | expect![[r#" |
1356 | detail: "i64", | 1140 | fd bar [type+name] |
1357 | }, | 1141 | fd baz [type] |
1358 | CompletionItem { | 1142 | fd foo [] |
1359 | label: "another_good_type", | 1143 | "#]], |
1360 | source_range: 189..189, | ||
1361 | delete: 189..189, | ||
1362 | insert: "another_good_type", | ||
1363 | kind: Field, | ||
1364 | detail: "u32", | ||
1365 | score: TypeMatch, | ||
1366 | }, | ||
1367 | CompletionItem { | ||
1368 | label: "the_field", | ||
1369 | source_range: 189..189, | ||
1370 | delete: 189..189, | ||
1371 | insert: "the_field", | ||
1372 | kind: Field, | ||
1373 | detail: "u32", | ||
1374 | score: TypeAndNameMatch, | ||
1375 | }, | ||
1376 | ] | ||
1377 | "### | ||
1378 | ); | 1144 | ); |
1379 | } | 1145 | } |
1380 | 1146 | ||
1381 | #[test] | 1147 | #[test] |
1382 | fn test_struct_field_completion_in_record_lit_and_fn_call() { | 1148 | fn prioritize_exact_ref_match() { |
1383 | assert_debug_snapshot!( | 1149 | check_scores( |
1384 | do_reference_completion( | 1150 | r#" |
1385 | r" | 1151 | struct WorldSnapshot { _f: () }; |
1386 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1152 | fn go(world: &WorldSnapshot) { go(w<|>) } |
1387 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | 1153 | "#, |
1388 | fn test(the_field: i64) -> i64 { the_field } | 1154 | expect![[r#" |
1389 | fn foo(a: A) { | 1155 | bn world [type+name] |
1390 | let b = B { | 1156 | st WorldSnapshot [] |
1391 | the_field: test(a.<|>) | 1157 | fn go(…) [] |
1392 | }; | 1158 | "#]], |
1393 | } | ||
1394 | ", | ||
1395 | ), | ||
1396 | @r###" | ||
1397 | [ | ||
1398 | CompletionItem { | ||
1399 | label: "another_field", | ||
1400 | source_range: 239..239, | ||
1401 | delete: 239..239, | ||
1402 | insert: "another_field", | ||
1403 | kind: Field, | ||
1404 | detail: "i64", | ||
1405 | score: TypeMatch, | ||
1406 | }, | ||
1407 | CompletionItem { | ||
1408 | label: "another_good_type", | ||
1409 | source_range: 239..239, | ||
1410 | delete: 239..239, | ||
1411 | insert: "another_good_type", | ||
1412 | kind: Field, | ||
1413 | detail: "u32", | ||
1414 | }, | ||
1415 | CompletionItem { | ||
1416 | label: "the_field", | ||
1417 | source_range: 239..239, | ||
1418 | delete: 239..239, | ||
1419 | insert: "the_field", | ||
1420 | kind: Field, | ||
1421 | detail: "u32", | ||
1422 | }, | ||
1423 | ] | ||
1424 | "### | ||
1425 | ); | 1159 | ); |
1426 | } | 1160 | } |
1427 | 1161 | ||
1428 | #[test] | 1162 | #[test] |
1429 | fn test_struct_field_completion_in_fn_call_and_record_lit() { | 1163 | fn too_many_arguments() { |
1430 | assert_debug_snapshot!( | 1164 | mark::check!(too_many_arguments); |
1431 | do_reference_completion( | 1165 | check_scores( |
1432 | r" | 1166 | r#" |
1433 | struct A { another_field: i64, another_good_type: u32, the_field: u32 } | 1167 | struct Foo; |
1434 | struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } | 1168 | fn f(foo: &Foo) { f(foo, w<|>) } |
1435 | fn test(the_field: i64) -> i64 { the_field } | 1169 | "#, |
1436 | fn foo(a: A) { | 1170 | expect![[r#" |
1437 | test(B { | 1171 | st Foo [] |
1438 | the_field: a.<|> | 1172 | fn f(…) [] |
1439 | }); | 1173 | bn foo [] |
1440 | } | 1174 | "#]], |
1441 | ", | ||
1442 | ), | ||
1443 | @r###" | ||
1444 | [ | ||
1445 | CompletionItem { | ||
1446 | label: "another_field", | ||
1447 | source_range: 231..231, | ||
1448 | delete: 231..231, | ||
1449 | insert: "another_field", | ||
1450 | kind: Field, | ||
1451 | detail: "i64", | ||
1452 | }, | ||
1453 | CompletionItem { | ||
1454 | label: "another_good_type", | ||
1455 | source_range: 231..231, | ||
1456 | delete: 231..231, | ||
1457 | insert: "another_good_type", | ||
1458 | kind: Field, | ||
1459 | detail: "u32", | ||
1460 | score: TypeMatch, | ||
1461 | }, | ||
1462 | CompletionItem { | ||
1463 | label: "the_field", | ||
1464 | source_range: 231..231, | ||
1465 | delete: 231..231, | ||
1466 | insert: "the_field", | ||
1467 | kind: Field, | ||
1468 | detail: "u32", | ||
1469 | score: TypeAndNameMatch, | ||
1470 | }, | ||
1471 | ] | ||
1472 | "### | ||
1473 | ); | 1175 | ); |
1474 | } | 1176 | } |
1475 | 1177 | ||
1476 | #[test] | 1178 | #[test] |
1477 | fn prioritize_exact_ref_match() { | 1179 | fn guesses_macro_braces() { |
1478 | assert_debug_snapshot!( | 1180 | check_edit( |
1479 | do_reference_completion( | 1181 | "vec!", |
1480 | r" | 1182 | r#" |
1481 | struct WorldSnapshot { _f: () }; | 1183 | /// Creates a [`Vec`] containing the arguments. |
1482 | fn go(world: &WorldSnapshot) { | 1184 | /// |
1483 | go(w<|>) | 1185 | /// ``` |
1484 | } | 1186 | /// let v = vec![1, 2, 3]; |
1485 | ", | 1187 | /// assert_eq!(v[0], 1); |
1486 | ), | 1188 | /// assert_eq!(v[1], 2); |
1487 | @r###" | 1189 | /// assert_eq!(v[2], 3); |
1488 | [ | 1190 | /// ``` |
1489 | CompletionItem { | 1191 | macro_rules! vec { () => {} } |
1490 | label: "WorldSnapshot", | 1192 | |
1491 | source_range: 71..72, | 1193 | fn fn main() { v<|> } |
1492 | delete: 71..72, | 1194 | "#, |
1493 | insert: "WorldSnapshot", | 1195 | r#" |
1494 | kind: Struct, | 1196 | /// Creates a [`Vec`] containing the arguments. |
1495 | }, | 1197 | /// |
1496 | CompletionItem { | 1198 | /// ``` |
1497 | label: "go(…)", | 1199 | /// let v = vec![1, 2, 3]; |
1498 | source_range: 71..72, | 1200 | /// assert_eq!(v[0], 1); |
1499 | delete: 71..72, | 1201 | /// assert_eq!(v[1], 2); |
1500 | insert: "go(${1:world})$0", | 1202 | /// assert_eq!(v[2], 3); |
1501 | kind: Function, | 1203 | /// ``` |
1502 | lookup: "go", | 1204 | macro_rules! vec { () => {} } |
1503 | detail: "fn go(world: &WorldSnapshot)", | 1205 | |
1504 | trigger_call_info: true, | 1206 | fn fn main() { vec![$0] } |
1505 | }, | 1207 | "#, |
1506 | CompletionItem { | ||
1507 | label: "world", | ||
1508 | source_range: 71..72, | ||
1509 | delete: 71..72, | ||
1510 | insert: "world", | ||
1511 | kind: Binding, | ||
1512 | detail: "&WorldSnapshot", | ||
1513 | score: TypeAndNameMatch, | ||
1514 | }, | ||
1515 | ] | ||
1516 | "### | ||
1517 | ); | 1208 | ); |
1209 | |||
1210 | check_edit( | ||
1211 | "foo!", | ||
1212 | r#" | ||
1213 | /// Foo | ||
1214 | /// | ||
1215 | /// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, | ||
1216 | /// call as `let _=foo! { hello world };` | ||
1217 | macro_rules! foo { () => {} } | ||
1218 | fn main() { <|> } | ||
1219 | "#, | ||
1220 | r#" | ||
1221 | /// Foo | ||
1222 | /// | ||
1223 | /// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, | ||
1224 | /// call as `let _=foo! { hello world };` | ||
1225 | macro_rules! foo { () => {} } | ||
1226 | fn main() { foo! {$0} } | ||
1227 | "#, | ||
1228 | ) | ||
1518 | } | 1229 | } |
1519 | } | 1230 | } |