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_keyword.rs31
-rw-r--r--crates/ra_ide/src/completion/presentation.rs466
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs11
3 files changed, 177 insertions, 331 deletions
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index 34d061f5a..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
@@ -180,6 +182,7 @@ mod tests {
180 test_utils::{check_edit, completion_list}, 182 test_utils::{check_edit, completion_list},
181 CompletionKind, 183 CompletionKind,
182 }; 184 };
185 use test_utils::mark;
183 186
184 fn check(ra_fixture: &str, expect: Expect) { 187 fn check(ra_fixture: &str, expect: Expect) {
185 let actual = completion_list(ra_fixture, CompletionKind::Keyword); 188 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
@@ -459,4 +462,32 @@ fn quux() -> i32 {
459 "#]], 462 "#]],
460 ); 463 );
461 } 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![[""]],
484 );
485 check(
486 r#"
487/// Some doc comment
488/// let test<|> = 1
489"#,
490 expect![[""]],
491 );
492 }
462} 493}
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index f472b9529..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::{check_edit, 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!(
@@ -647,6 +645,7 @@ fn no_args() {}
647fn main() { no_args()$0 } 645fn main() { no_args()$0 }
648"#, 646"#,
649 ); 647 );
648
650 check_edit( 649 check_edit(
651 "with_args", 650 "with_args",
652 r#" 651 r#"
@@ -658,6 +657,7 @@ fn with_args(x: i32, y: String) {}
658fn main() { with_args(${1:x}, ${2:y})$0 } 657fn main() { with_args(${1:x}, ${2:y})$0 }
659"#, 658"#,
660 ); 659 );
660
661 check_edit( 661 check_edit(
662 "foo", 662 "foo",
663 r#" 663 r#"
@@ -675,6 +675,45 @@ impl S {
675fn bar(s: &S) { s.foo()$0 } 675fn bar(s: &S) { s.foo()$0 }
676"#, 676"#,
677 ); 677 );
678
679 check_edit(
680 "foo",
681 r#"
682struct S {}
683impl S {
684 fn foo(&self, x: i32) {}
685}
686fn bar(s: &S) {
687 s.f<|>
688}
689"#,
690 r#"
691struct S {}
692impl S {
693 fn foo(&self, x: i32) {}
694}
695fn bar(s: &S) {
696 s.foo(${1:x})$0
697}
698"#,
699 );
700 }
701
702 #[test]
703 fn suppress_arg_snippets() {
704 mark::check!(suppress_arg_snippets);
705 check_edit_with_config(
706 "with_args",
707 r#"
708fn with_args(x: i32, y: String) {}
709fn main() { with_<|> }
710"#,
711 r#"
712fn with_args(x: i32, y: String) {}
713fn main() { with_args($0) }
714"#,
715 &CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
716 );
678 } 717 }
679 718
680 #[test] 719 #[test]
@@ -694,294 +733,111 @@ fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
694 733
695 #[test] 734 #[test]
696 fn inserts_parens_for_tuple_enums() { 735 fn inserts_parens_for_tuple_enums() {
697 assert_debug_snapshot!( 736 check_edit(
698 do_reference_completion( 737 "Some",
699 r" 738 r#"
700 enum Option<T> { Some(T), None } 739enum Option<T> { Some(T), None }
701 use Option::*; 740use Option::*;
702 fn main() -> Option<i32> { 741fn main() -> Option<i32> {
703 Som<|> 742 Som<|>
704 } 743}
705 " 744"#,
706 ), 745 r#"
707 @r###" 746enum Option<T> { Some(T), None }
708 [ 747use Option::*;
709 CompletionItem { 748fn main() -> Option<i32> {
710 label: "None", 749 Some($0)
711 source_range: 79..82, 750}
712 delete: 79..82, 751"#,
713 insert: "None",
714 kind: EnumVariant,
715 detail: "()",
716 },
717 CompletionItem {
718 label: "Option",
719 source_range: 79..82,
720 delete: 79..82,
721 insert: "Option",
722 kind: Enum,
723 },
724 CompletionItem {
725 label: "Some(…)",
726 source_range: 79..82,
727 delete: 79..82,
728 insert: "Some($0)",
729 kind: EnumVariant,
730 lookup: "Some",
731 detail: "(T)",
732 trigger_call_info: true,
733 },
734 CompletionItem {
735 label: "main()",
736 source_range: 79..82,
737 delete: 79..82,
738 insert: "main()$0",
739 kind: Function,
740 lookup: "main",
741 detail: "fn main() -> Option<i32>",
742 },
743 ]
744 "###
745 ); 752 );
746 assert_debug_snapshot!( 753 check_edit(
747 do_reference_completion( 754 "Some",
748 r" 755 r#"
749 enum Option<T> { Some(T), None } 756enum Option<T> { Some(T), None }
750 use Option::*; 757use Option::*;
751 fn main(value: Option<i32>) { 758fn main(value: Option<i32>) {
752 match value { 759 match value {
753 Som<|> 760 Som<|>
754 } 761 }
755 } 762}
756 " 763"#,
757 ), 764 r#"
758 @r###" 765enum Option<T> { Some(T), None }
759 [ 766use Option::*;
760 CompletionItem { 767fn main(value: Option<i32>) {
761 label: "None", 768 match value {
762 source_range: 104..107, 769 Some($0)
763 delete: 104..107, 770 }
764 insert: "None", 771}
765 kind: EnumVariant, 772"#,
766 detail: "()",
767 },
768 CompletionItem {
769 label: "Option",
770 source_range: 104..107,
771 delete: 104..107,
772 insert: "Option",
773 kind: Enum,
774 },
775 CompletionItem {
776 label: "Some(…)",
777 source_range: 104..107,
778 delete: 104..107,
779 insert: "Some($0)",
780 kind: EnumVariant,
781 lookup: "Some",
782 detail: "(T)",
783 trigger_call_info: true,
784 },
785 ]
786 "###
787 ); 773 );
788 } 774 }
789 775
790 #[test] 776 #[test]
791 fn no_call_parens_if_fn_ptr_needed() { 777 fn no_call_parens_if_fn_ptr_needed() {
792 assert_debug_snapshot!( 778 mark::check!(no_call_parens_if_fn_ptr_needed);
793 do_reference_completion( 779 check_edit(
794 r" 780 "foo",
795 fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8) {} 781 r#"
782fn foo(foo: u8, bar: u8) {}
783struct ManualVtable { f: fn(u8, u8) }
796 784
797 struct ManualVtable { 785fn main() -> ManualVtable {
798 method: fn(u8, u8, u8, u8, u8), 786 ManualVtable { f: f<|> }
799 } 787}
788"#,
789 r#"
790fn foo(foo: u8, bar: u8) {}
791struct ManualVtable { f: fn(u8, u8) }
800 792
801 fn main() -> ManualVtable { 793fn main() -> ManualVtable {
802 ManualVtable { 794 ManualVtable { f: foo }
803 method: some<|> 795}
804 } 796"#,
805 }
806 "
807 ),
808 @r###"
809 [
810 CompletionItem {
811 label: "ManualVtable",
812 source_range: 182..186,
813 delete: 182..186,
814 insert: "ManualVtable",
815 kind: Struct,
816 },
817 CompletionItem {
818 label: "main",
819 source_range: 182..186,
820 delete: 182..186,
821 insert: "main",
822 kind: Function,
823 detail: "fn main() -> ManualVtable",
824 },
825 CompletionItem {
826 label: "somefn",
827 source_range: 182..186,
828 delete: 182..186,
829 insert: "somefn",
830 kind: Function,
831 detail: "fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8)",
832 },
833 ]
834 "###
835 ); 797 );
836 } 798 }
837 799
838 #[test] 800 #[test]
839 fn arg_snippets_for_method_call() { 801 fn no_parens_in_use_item() {
840 assert_debug_snapshot!( 802 mark::check!(no_parens_in_use_item);
841 do_reference_completion( 803 check_edit(
842 r" 804 "foo",
843 struct S {} 805 r#"
844 impl S { 806mod m { pub fn foo() {} }
845 fn foo(&self, x: i32) {} 807use crate::m::f<|>;
846 } 808"#,
847 fn bar(s: &S) { 809 r#"
848 s.f<|> 810mod m { pub fn foo() {} }
849 } 811use crate::m::foo;
850 " 812"#,
851 ),
852 @r###"
853 [
854 CompletionItem {
855 label: "foo(…)",
856 source_range: 74..75,
857 delete: 74..75,
858 insert: "foo(${1:x})$0",
859 kind: Method,
860 lookup: "foo",
861 detail: "fn foo(&self, x: i32)",
862 trigger_call_info: true,
863 },
864 ]
865 "###
866 )
867 }
868
869 #[test]
870 fn no_arg_snippets_for_method_call() {
871 assert_debug_snapshot!(
872 do_reference_completion_with_options(
873 r"
874 struct S {}
875 impl S {
876 fn foo(&self, x: i32) {}
877 }
878 fn bar(s: &S) {
879 s.f<|>
880 }
881 ",
882 CompletionConfig {
883 add_call_argument_snippets: false,
884 .. Default::default()
885 }
886 ),
887 @r###"
888 [
889 CompletionItem {
890 label: "foo(…)",
891 source_range: 74..75,
892 delete: 74..75,
893 insert: "foo($0)",
894 kind: Method,
895 lookup: "foo",
896 detail: "fn foo(&self, x: i32)",
897 trigger_call_info: true,
898 },
899 ]
900 "###
901 )
902 }
903
904 #[test]
905 fn dont_render_function_parens_in_use_item() {
906 assert_debug_snapshot!(
907 do_reference_completion(
908 "
909 //- /lib.rs
910 mod m { pub fn foo() {} }
911 use crate::m::f<|>;
912 "
913 ),
914 @r###"
915 [
916 CompletionItem {
917 label: "foo",
918 source_range: 40..41,
919 delete: 40..41,
920 insert: "foo",
921 kind: Function,
922 detail: "pub fn foo()",
923 },
924 ]
925 "###
926 ); 813 );
927 } 814 }
928 815
929 #[test] 816 #[test]
930 fn dont_render_function_parens_if_already_call() { 817 fn no_parens_in_call() {
931 assert_debug_snapshot!( 818 check_edit(
932 do_reference_completion( 819 "foo",
933 " 820 r#"
934 //- /lib.rs 821fn foo(x: i32) {}
935 fn frobnicate() {} 822fn main() { f<|>(); }
936 fn main() { 823"#,
937 frob<|>(); 824 r#"
938 } 825fn foo(x: i32) {}
939 " 826fn main() { foo(); }
940 ), 827"#,
941 @r###"
942 [
943 CompletionItem {
944 label: "frobnicate",
945 source_range: 35..39,
946 delete: 35..39,
947 insert: "frobnicate",
948 kind: Function,
949 detail: "fn frobnicate()",
950 },
951 CompletionItem {
952 label: "main",
953 source_range: 35..39,
954 delete: 35..39,
955 insert: "main",
956 kind: Function,
957 detail: "fn main()",
958 },
959 ]
960 "###
961 ); 828 );
962 assert_debug_snapshot!( 829 check_edit(
963 do_reference_completion( 830 "foo",
964 " 831 r#"
965 //- /lib.rs 832struct Foo;
966 struct Foo {} 833impl Foo { fn foo(&self){} }
967 impl Foo { fn new() -> Foo {} } 834fn f(foo: &Foo) { foo.f<|>(); }
968 fn main() { 835"#,
969 Foo::ne<|>(); 836 r#"
970 } 837struct Foo;
971 " 838impl Foo { fn foo(&self){} }
972 ), 839fn f(foo: &Foo) { foo.foo(); }
973 @r###" 840"#,
974 [
975 CompletionItem {
976 label: "new",
977 source_range: 67..69,
978 delete: 67..69,
979 insert: "new",
980 kind: Function,
981 detail: "fn new() -> Foo",
982 },
983 ]
984 "###
985 ); 841 );
986 } 842 }
987 843
@@ -1450,54 +1306,4 @@ fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
1450 "### 1306 "###
1451 ); 1307 );
1452 } 1308 }
1453
1454 #[test]
1455 fn no_keyword_autocompletion_on_line_comments() {
1456 assert_debug_snapshot!(
1457 do_completion(
1458 r"
1459 fn test() {
1460 let x = 2; // A comment<|>
1461 }
1462 ",
1463 CompletionKind::Keyword
1464 ),
1465 @r###"
1466 []
1467 "###
1468 );
1469 }
1470
1471 #[test]
1472 fn no_keyword_autocompletion_on_multi_line_comments() {
1473 assert_debug_snapshot!(
1474 do_completion(
1475 r"
1476 /*
1477 Some multi-line comment<|>
1478 */
1479 ",
1480 CompletionKind::Keyword
1481 ),
1482 @r###"
1483 []
1484 "###
1485 );
1486 }
1487
1488 #[test]
1489 fn no_keyword_autocompletion_on_doc_comments() {
1490 assert_debug_snapshot!(
1491 do_completion(
1492 r"
1493 /// Some doc comment
1494 /// let test<|> = 1
1495 ",
1496 CompletionKind::Keyword
1497 ),
1498 @r###"
1499 []
1500 "###
1501 );
1502 }
1503} 1309}
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index f25190241..145d36c98 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -57,10 +57,19 @@ pub(crate) fn completion_list_with_options(
57} 57}
58 58
59pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 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) {
60 let ra_fixture_after = trim_indent(ra_fixture_after); 69 let ra_fixture_after = trim_indent(ra_fixture_after);
61 let (analysis, position) = analysis_and_position(ra_fixture_before); 70 let (analysis, position) = analysis_and_position(ra_fixture_before);
62 let completions: Vec<CompletionItem> = 71 let completions: Vec<CompletionItem> =
63 analysis.completions(&CompletionConfig::default(), position).unwrap().unwrap().into(); 72 analysis.completions(config, position).unwrap().unwrap().into();
64 let (completion,) = completions 73 let (completion,) = completions
65 .iter() 74 .iter()
66 .filter(|it| it.lookup() == what) 75 .filter(|it| it.lookup() == what)