diff options
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 65 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_fn_param.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_keyword.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_macro_in_item_position.rs | 3 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_path.rs | 72 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_pattern.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_postfix.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_record_literal.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_record_pattern.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_scope.rs | 42 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_snippet.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 146 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 22 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 86 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/test_utils.rs | 29 |
16 files changed, 416 insertions, 70 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index f275305e2..f07611d88 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -70,7 +70,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T | |||
70 | 70 | ||
71 | #[cfg(test)] | 71 | #[cfg(test)] |
72 | mod tests { | 72 | mod tests { |
73 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 73 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
74 | use insta::assert_debug_snapshot; | 74 | use insta::assert_debug_snapshot; |
75 | 75 | ||
76 | fn do_ref_completion(code: &str) -> Vec<CompletionItem> { | 76 | fn do_ref_completion(code: &str) -> Vec<CompletionItem> { |
@@ -402,6 +402,38 @@ mod tests { | |||
402 | } | 402 | } |
403 | 403 | ||
404 | #[test] | 404 | #[test] |
405 | fn completes_trait_method_from_other_module() { | ||
406 | assert_debug_snapshot!( | ||
407 | do_ref_completion( | ||
408 | r" | ||
409 | struct A {} | ||
410 | mod m { | ||
411 | pub trait Trait { fn the_method(&self); } | ||
412 | } | ||
413 | use m::Trait; | ||
414 | impl Trait for A {} | ||
415 | fn foo(a: A) { | ||
416 | a.<|> | ||
417 | } | ||
418 | ", | ||
419 | ), | ||
420 | @r###" | ||
421 | [ | ||
422 | CompletionItem { | ||
423 | label: "the_method()", | ||
424 | source_range: [219; 219), | ||
425 | delete: [219; 219), | ||
426 | insert: "the_method()$0", | ||
427 | kind: Method, | ||
428 | lookup: "the_method", | ||
429 | detail: "fn the_method(&self)", | ||
430 | }, | ||
431 | ] | ||
432 | "### | ||
433 | ); | ||
434 | } | ||
435 | |||
436 | #[test] | ||
405 | fn test_no_non_self_method() { | 437 | fn test_no_non_self_method() { |
406 | assert_debug_snapshot!( | 438 | assert_debug_snapshot!( |
407 | do_ref_completion( | 439 | do_ref_completion( |
@@ -718,4 +750,35 @@ mod tests { | |||
718 | "### | 750 | "### |
719 | ); | 751 | ); |
720 | } | 752 | } |
753 | |||
754 | #[test] | ||
755 | fn test_method_completion_3547() { | ||
756 | assert_debug_snapshot!( | ||
757 | do_ref_completion( | ||
758 | r" | ||
759 | struct HashSet<T> {} | ||
760 | impl<T> HashSet<T> { | ||
761 | pub fn the_method(&self) {} | ||
762 | } | ||
763 | fn foo() { | ||
764 | let s: HashSet<_>; | ||
765 | s.<|> | ||
766 | } | ||
767 | ", | ||
768 | ), | ||
769 | @r###" | ||
770 | [ | ||
771 | CompletionItem { | ||
772 | label: "the_method()", | ||
773 | source_range: [201; 201), | ||
774 | delete: [201; 201), | ||
775 | insert: "the_method()$0", | ||
776 | kind: Method, | ||
777 | lookup: "the_method", | ||
778 | detail: "pub fn the_method(&self)", | ||
779 | }, | ||
780 | ] | ||
781 | "### | ||
782 | ); | ||
783 | } | ||
721 | } | 784 | } |
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs index 502458706..9226ac055 100644 --- a/crates/ra_ide/src/completion/complete_fn_param.rs +++ b/crates/ra_ide/src/completion/complete_fn_param.rs | |||
@@ -52,7 +52,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
52 | 52 | ||
53 | #[cfg(test)] | 53 | #[cfg(test)] |
54 | mod tests { | 54 | mod tests { |
55 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 55 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
56 | use insta::assert_debug_snapshot; | 56 | use insta::assert_debug_snapshot; |
57 | 57 | ||
58 | fn do_magic_completion(code: &str) -> Vec<CompletionItem> { | 58 | fn do_magic_completion(code: &str) -> Vec<CompletionItem> { |
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index e1c0ffb1f..1e053ea4a 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs | |||
@@ -117,7 +117,7 @@ fn complete_return( | |||
117 | 117 | ||
118 | #[cfg(test)] | 118 | #[cfg(test)] |
119 | mod tests { | 119 | mod tests { |
120 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 120 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
121 | use insta::assert_debug_snapshot; | 121 | use insta::assert_debug_snapshot; |
122 | 122 | ||
123 | fn do_keyword_completion(code: &str) -> Vec<CompletionItem> { | 123 | fn do_keyword_completion(code: &str) -> Vec<CompletionItem> { |
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs index 1866d9e6c..270e96df0 100644 --- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs +++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs | |||
@@ -15,9 +15,10 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl | |||
15 | 15 | ||
16 | #[cfg(test)] | 16 | #[cfg(test)] |
17 | mod tests { | 17 | mod tests { |
18 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
19 | use insta::assert_debug_snapshot; | 18 | use insta::assert_debug_snapshot; |
20 | 19 | ||
20 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
21 | |||
21 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { | 22 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { |
22 | do_completion(code, CompletionKind::Reference) | 23 | do_completion(code, CompletionKind::Reference) |
23 | } | 24 | } |
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs index 3c4a70561..3db17f15f 100644 --- a/crates/ra_ide/src/completion/complete_path.rs +++ b/crates/ra_ide/src/completion/complete_path.rs | |||
@@ -103,7 +103,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
103 | mod tests { | 103 | mod tests { |
104 | use test_utils::covers; | 104 | use test_utils::covers; |
105 | 105 | ||
106 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 106 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
107 | use insta::assert_debug_snapshot; | 107 | use insta::assert_debug_snapshot; |
108 | 108 | ||
109 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { | 109 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { |
@@ -967,4 +967,74 @@ mod tests { | |||
967 | ] | 967 | ] |
968 | "###); | 968 | "###); |
969 | } | 969 | } |
970 | |||
971 | #[test] | ||
972 | fn function_mod_share_name() { | ||
973 | assert_debug_snapshot!( | ||
974 | do_reference_completion( | ||
975 | r" | ||
976 | fn foo() { | ||
977 | self::m::<|> | ||
978 | } | ||
979 | |||
980 | mod m { | ||
981 | pub mod z {} | ||
982 | pub fn z() {} | ||
983 | } | ||
984 | ", | ||
985 | ), | ||
986 | @r###" | ||
987 | [ | ||
988 | CompletionItem { | ||
989 | label: "z", | ||
990 | source_range: [57; 57), | ||
991 | delete: [57; 57), | ||
992 | insert: "z", | ||
993 | kind: Module, | ||
994 | }, | ||
995 | CompletionItem { | ||
996 | label: "z()", | ||
997 | source_range: [57; 57), | ||
998 | delete: [57; 57), | ||
999 | insert: "z()$0", | ||
1000 | kind: Function, | ||
1001 | lookup: "z", | ||
1002 | detail: "pub fn z()", | ||
1003 | }, | ||
1004 | ] | ||
1005 | "### | ||
1006 | ); | ||
1007 | } | ||
1008 | |||
1009 | #[test] | ||
1010 | fn completes_hashmap_new() { | ||
1011 | assert_debug_snapshot!( | ||
1012 | do_reference_completion( | ||
1013 | r" | ||
1014 | struct RandomState; | ||
1015 | struct HashMap<K, V, S = RandomState> {} | ||
1016 | |||
1017 | impl<K, V> HashMap<K, V, RandomState> { | ||
1018 | pub fn new() -> HashMap<K, V, RandomState> { } | ||
1019 | } | ||
1020 | fn foo() { | ||
1021 | HashMap::<|> | ||
1022 | } | ||
1023 | " | ||
1024 | ), | ||
1025 | @r###" | ||
1026 | [ | ||
1027 | CompletionItem { | ||
1028 | label: "new()", | ||
1029 | source_range: [292; 292), | ||
1030 | delete: [292; 292), | ||
1031 | insert: "new()$0", | ||
1032 | kind: Function, | ||
1033 | lookup: "new", | ||
1034 | detail: "pub fn new() -> HashMap<K, V, RandomState>", | ||
1035 | }, | ||
1036 | ] | ||
1037 | "### | ||
1038 | ); | ||
1039 | } | ||
970 | } | 1040 | } |
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs index fa8aeceda..6a1a66ef1 100644 --- a/crates/ra_ide/src/completion/complete_pattern.rs +++ b/crates/ra_ide/src/completion/complete_pattern.rs | |||
@@ -27,7 +27,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
27 | 27 | ||
28 | #[cfg(test)] | 28 | #[cfg(test)] |
29 | mod tests { | 29 | mod tests { |
30 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 30 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
31 | use insta::assert_debug_snapshot; | 31 | use insta::assert_debug_snapshot; |
32 | 32 | ||
33 | fn complete(code: &str) -> Vec<CompletionItem> { | 33 | fn complete(code: &str) -> Vec<CompletionItem> { |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 65ecea125..0ba382165 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | }; | 12 | }; |
13 | 13 | ||
14 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | 14 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
15 | if !ctx.db.feature_flags.get("completion.enable-postfix") { | 15 | if !ctx.options.enable_postfix_completions { |
16 | return; | 16 | return; |
17 | } | 17 | } |
18 | 18 | ||
@@ -81,7 +81,7 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: | |||
81 | mod tests { | 81 | mod tests { |
82 | use insta::assert_debug_snapshot; | 82 | use insta::assert_debug_snapshot; |
83 | 83 | ||
84 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 84 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
85 | 85 | ||
86 | fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { | 86 | fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { |
87 | do_completion(code, CompletionKind::Postfix) | 87 | do_completion(code, CompletionKind::Postfix) |
diff --git a/crates/ra_ide/src/completion/complete_record_literal.rs b/crates/ra_ide/src/completion/complete_record_literal.rs index be6e4194f..83ed1d52c 100644 --- a/crates/ra_ide/src/completion/complete_record_literal.rs +++ b/crates/ra_ide/src/completion/complete_record_literal.rs | |||
@@ -18,7 +18,7 @@ pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionCon | |||
18 | 18 | ||
19 | #[cfg(test)] | 19 | #[cfg(test)] |
20 | mod tests { | 20 | mod tests { |
21 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 21 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
22 | use insta::assert_debug_snapshot; | 22 | use insta::assert_debug_snapshot; |
23 | 23 | ||
24 | fn complete(code: &str) -> Vec<CompletionItem> { | 24 | fn complete(code: &str) -> Vec<CompletionItem> { |
diff --git a/crates/ra_ide/src/completion/complete_record_pattern.rs b/crates/ra_ide/src/completion/complete_record_pattern.rs index 687c57d3e..962376428 100644 --- a/crates/ra_ide/src/completion/complete_record_pattern.rs +++ b/crates/ra_ide/src/completion/complete_record_pattern.rs | |||
@@ -17,7 +17,7 @@ pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionCon | |||
17 | 17 | ||
18 | #[cfg(test)] | 18 | #[cfg(test)] |
19 | mod tests { | 19 | mod tests { |
20 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 20 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
21 | use insta::assert_debug_snapshot; | 21 | use insta::assert_debug_snapshot; |
22 | 22 | ||
23 | fn complete(code: &str) -> Vec<CompletionItem> { | 23 | fn complete(code: &str) -> Vec<CompletionItem> { |
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs index eb3c8cf1b..5ffff5a1c 100644 --- a/crates/ra_ide/src/completion/complete_scope.rs +++ b/crates/ra_ide/src/completion/complete_scope.rs | |||
@@ -14,10 +14,10 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | |||
14 | mod tests { | 14 | mod tests { |
15 | use insta::assert_debug_snapshot; | 15 | use insta::assert_debug_snapshot; |
16 | 16 | ||
17 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 17 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
18 | 18 | ||
19 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { | 19 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { |
20 | do_completion(code, CompletionKind::Reference) | 20 | do_completion(ra_fixture, CompletionKind::Reference) |
21 | } | 21 | } |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
@@ -42,6 +42,7 @@ mod tests { | |||
42 | kind: Function, | 42 | kind: Function, |
43 | lookup: "quux", | 43 | lookup: "quux", |
44 | detail: "fn quux(x: i32)", | 44 | detail: "fn quux(x: i32)", |
45 | trigger_call_info: true, | ||
45 | }, | 46 | }, |
46 | CompletionItem { | 47 | CompletionItem { |
47 | label: "x", | 48 | label: "x", |
@@ -844,6 +845,7 @@ mod tests { | |||
844 | kind: Function, | 845 | kind: Function, |
845 | lookup: "quux", | 846 | lookup: "quux", |
846 | detail: "fn quux(x: i32)", | 847 | detail: "fn quux(x: i32)", |
848 | trigger_call_info: true, | ||
847 | }, | 849 | }, |
848 | CompletionItem { | 850 | CompletionItem { |
849 | label: "x", | 851 | label: "x", |
@@ -865,4 +867,38 @@ mod tests { | |||
865 | "### | 867 | "### |
866 | ); | 868 | ); |
867 | } | 869 | } |
870 | |||
871 | #[test] | ||
872 | fn completes_unresolved_uses() { | ||
873 | assert_debug_snapshot!( | ||
874 | do_reference_completion( | ||
875 | r" | ||
876 | use spam::Quux; | ||
877 | |||
878 | fn main() { | ||
879 | <|> | ||
880 | } | ||
881 | " | ||
882 | ), | ||
883 | @r###" | ||
884 | [ | ||
885 | CompletionItem { | ||
886 | label: "Quux", | ||
887 | source_range: [82; 82), | ||
888 | delete: [82; 82), | ||
889 | insert: "Quux", | ||
890 | }, | ||
891 | CompletionItem { | ||
892 | label: "main()", | ||
893 | source_range: [82; 82), | ||
894 | delete: [82; 82), | ||
895 | insert: "main()$0", | ||
896 | kind: Function, | ||
897 | lookup: "main", | ||
898 | detail: "fn main()", | ||
899 | }, | ||
900 | ] | ||
901 | "### | ||
902 | ); | ||
903 | } | ||
868 | } | 904 | } |
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index 731b4fd82..f731e9b9a 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs | |||
@@ -42,7 +42,7 @@ fn ${1:feature}() { | |||
42 | 42 | ||
43 | #[cfg(test)] | 43 | #[cfg(test)] |
44 | mod tests { | 44 | mod tests { |
45 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 45 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
46 | use insta::assert_debug_snapshot; | 46 | use insta::assert_debug_snapshot; |
47 | 47 | ||
48 | fn do_snippet_completion(code: &str) -> Vec<CompletionItem> { | 48 | fn do_snippet_completion(code: &str) -> Vec<CompletionItem> { |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 18a1d2995..7fefa2c7a 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -34,7 +34,7 @@ | |||
34 | use hir::{self, Docs, HasSource}; | 34 | use hir::{self, Docs, HasSource}; |
35 | use ra_assists::utils::get_missing_impl_items; | 35 | use ra_assists::utils::get_missing_impl_items; |
36 | use ra_syntax::{ | 36 | use ra_syntax::{ |
37 | ast::{self, edit}, | 37 | ast::{self, edit, ImplDef}, |
38 | AstNode, SyntaxKind, SyntaxNode, TextRange, | 38 | AstNode, SyntaxKind, SyntaxNode, TextRange, |
39 | }; | 39 | }; |
40 | use ra_text_edit::TextEdit; | 40 | use ra_text_edit::TextEdit; |
@@ -47,22 +47,22 @@ use crate::{ | |||
47 | }; | 47 | }; |
48 | 48 | ||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
50 | let trigger = ctx.token.ancestors().find(|p| match p.kind() { | 50 | if let Some((trigger, impl_def)) = completion_match(ctx) { |
51 | SyntaxKind::FN_DEF | ||
52 | | SyntaxKind::TYPE_ALIAS_DEF | ||
53 | | SyntaxKind::CONST_DEF | ||
54 | | SyntaxKind::BLOCK_EXPR => true, | ||
55 | _ => false, | ||
56 | }); | ||
57 | |||
58 | let impl_def = trigger | ||
59 | .as_ref() | ||
60 | .and_then(|node| node.parent()) | ||
61 | .and_then(|node| node.parent()) | ||
62 | .and_then(ast::ImplDef::cast); | ||
63 | |||
64 | if let (Some(trigger), Some(impl_def)) = (trigger, impl_def) { | ||
65 | match trigger.kind() { | 51 | match trigger.kind() { |
52 | SyntaxKind::NAME_REF => { | ||
53 | get_missing_impl_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { | ||
54 | hir::AssocItem::Function(fn_item) => { | ||
55 | add_function_impl(&trigger, acc, ctx, &fn_item) | ||
56 | } | ||
57 | hir::AssocItem::TypeAlias(type_item) => { | ||
58 | add_type_alias_impl(&trigger, acc, ctx, &type_item) | ||
59 | } | ||
60 | hir::AssocItem::Const(const_item) => { | ||
61 | add_const_impl(&trigger, acc, ctx, &const_item) | ||
62 | } | ||
63 | }) | ||
64 | } | ||
65 | |||
66 | SyntaxKind::FN_DEF => { | 66 | SyntaxKind::FN_DEF => { |
67 | for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( | 67 | for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( |
68 | |item| match item { | 68 | |item| match item { |
@@ -101,6 +101,21 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> { | ||
105 | let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() { | ||
106 | SyntaxKind::FN_DEF | ||
107 | | SyntaxKind::TYPE_ALIAS_DEF | ||
108 | | SyntaxKind::CONST_DEF | ||
109 | | SyntaxKind::BLOCK_EXPR => Some((p, 2)), | ||
110 | SyntaxKind::NAME_REF => Some((p, 5)), | ||
111 | _ => None, | ||
112 | })?; | ||
113 | let impl_def = (0..impl_def_offset - 1) | ||
114 | .try_fold(trigger.parent()?, |t, _| t.parent()) | ||
115 | .and_then(ast::ImplDef::cast)?; | ||
116 | Some((trigger, impl_def)) | ||
117 | } | ||
118 | |||
104 | fn add_function_impl( | 119 | fn add_function_impl( |
105 | fn_def_node: &SyntaxNode, | 120 | fn_def_node: &SyntaxNode, |
106 | acc: &mut Completions, | 121 | acc: &mut Completions, |
@@ -202,7 +217,7 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { | |||
202 | 217 | ||
203 | #[cfg(test)] | 218 | #[cfg(test)] |
204 | mod tests { | 219 | mod tests { |
205 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 220 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
206 | use insta::assert_debug_snapshot; | 221 | use insta::assert_debug_snapshot; |
207 | 222 | ||
208 | fn complete(code: &str) -> Vec<CompletionItem> { | 223 | fn complete(code: &str) -> Vec<CompletionItem> { |
@@ -210,6 +225,103 @@ mod tests { | |||
210 | } | 225 | } |
211 | 226 | ||
212 | #[test] | 227 | #[test] |
228 | fn name_ref_function_type_const() { | ||
229 | let completions = complete( | ||
230 | r" | ||
231 | trait Test { | ||
232 | type TestType; | ||
233 | const TEST_CONST: u16; | ||
234 | fn test(); | ||
235 | } | ||
236 | |||
237 | struct T1; | ||
238 | |||
239 | impl Test for T1 { | ||
240 | t<|> | ||
241 | } | ||
242 | ", | ||
243 | ); | ||
244 | assert_debug_snapshot!(completions, @r###" | ||
245 | [ | ||
246 | CompletionItem { | ||
247 | label: "const TEST_CONST: u16 = ", | ||
248 | source_range: [209; 210), | ||
249 | delete: [209; 210), | ||
250 | insert: "const TEST_CONST: u16 = ", | ||
251 | kind: Const, | ||
252 | lookup: "TEST_CONST", | ||
253 | }, | ||
254 | CompletionItem { | ||
255 | label: "fn test()", | ||
256 | source_range: [209; 210), | ||
257 | delete: [209; 210), | ||
258 | insert: "fn test() {}", | ||
259 | kind: Function, | ||
260 | lookup: "test", | ||
261 | }, | ||
262 | CompletionItem { | ||
263 | label: "type TestType = ", | ||
264 | source_range: [209; 210), | ||
265 | delete: [209; 210), | ||
266 | insert: "type TestType = ", | ||
267 | kind: TypeAlias, | ||
268 | lookup: "TestType", | ||
269 | }, | ||
270 | ] | ||
271 | "###); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
275 | fn no_nested_fn_completions() { | ||
276 | let completions = complete( | ||
277 | r" | ||
278 | trait Test { | ||
279 | fn test(); | ||
280 | fn test2(); | ||
281 | } | ||
282 | |||
283 | struct T1; | ||
284 | |||
285 | impl Test for T1 { | ||
286 | fn test() { | ||
287 | t<|> | ||
288 | } | ||
289 | } | ||
290 | ", | ||
291 | ); | ||
292 | assert_debug_snapshot!(completions, @r###"[]"###); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn name_ref_single_function() { | ||
297 | let completions = complete( | ||
298 | r" | ||
299 | trait Test { | ||
300 | fn test(); | ||
301 | } | ||
302 | |||
303 | struct T1; | ||
304 | |||
305 | impl Test for T1 { | ||
306 | t<|> | ||
307 | } | ||
308 | ", | ||
309 | ); | ||
310 | assert_debug_snapshot!(completions, @r###" | ||
311 | [ | ||
312 | CompletionItem { | ||
313 | label: "fn test()", | ||
314 | source_range: [139; 140), | ||
315 | delete: [139; 140), | ||
316 | insert: "fn test() {}", | ||
317 | kind: Function, | ||
318 | lookup: "test", | ||
319 | }, | ||
320 | ] | ||
321 | "###); | ||
322 | } | ||
323 | |||
324 | #[test] | ||
213 | fn single_function() { | 325 | fn single_function() { |
214 | let completions = complete( | 326 | let completions = complete( |
215 | r" | 327 | r" |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 40535c09e..3646fb8dc 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | }; | 11 | }; |
12 | use ra_text_edit::AtomTextEdit; | 12 | use ra_text_edit::AtomTextEdit; |
13 | 13 | ||
14 | use crate::FilePosition; | 14 | use crate::{completion::CompletionOptions, FilePosition}; |
15 | 15 | ||
16 | /// `CompletionContext` is created early during completion to figure out, where | 16 | /// `CompletionContext` is created early during completion to figure out, where |
17 | /// exactly is the cursor, syntax-wise. | 17 | /// exactly is the cursor, syntax-wise. |
@@ -19,6 +19,7 @@ use crate::FilePosition; | |||
19 | pub(crate) struct CompletionContext<'a> { | 19 | pub(crate) struct CompletionContext<'a> { |
20 | pub(super) sema: Semantics<'a, RootDatabase>, | 20 | pub(super) sema: Semantics<'a, RootDatabase>, |
21 | pub(super) db: &'a RootDatabase, | 21 | pub(super) db: &'a RootDatabase, |
22 | pub(super) options: &'a CompletionOptions, | ||
22 | pub(super) offset: TextUnit, | 23 | pub(super) offset: TextUnit, |
23 | /// The token before the cursor, in the original file. | 24 | /// The token before the cursor, in the original file. |
24 | pub(super) original_token: SyntaxToken, | 25 | pub(super) original_token: SyntaxToken, |
@@ -57,6 +58,7 @@ impl<'a> CompletionContext<'a> { | |||
57 | pub(super) fn new( | 58 | pub(super) fn new( |
58 | db: &'a RootDatabase, | 59 | db: &'a RootDatabase, |
59 | position: FilePosition, | 60 | position: FilePosition, |
61 | options: &'a CompletionOptions, | ||
60 | ) -> Option<CompletionContext<'a>> { | 62 | ) -> Option<CompletionContext<'a>> { |
61 | let sema = Semantics::new(db); | 63 | let sema = Semantics::new(db); |
62 | 64 | ||
@@ -80,6 +82,7 @@ impl<'a> CompletionContext<'a> { | |||
80 | let mut ctx = CompletionContext { | 82 | let mut ctx = CompletionContext { |
81 | sema, | 83 | sema, |
82 | db, | 84 | db, |
85 | options, | ||
83 | original_token, | 86 | original_token, |
84 | token, | 87 | token, |
85 | offset: position.offset, | 88 | offset: position.offset, |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 19bbb2517..bc0f1aff5 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -13,7 +13,7 @@ pub struct CompletionItem { | |||
13 | /// Used only internally in tests, to check only specific kind of | 13 | /// Used only internally in tests, to check only specific kind of |
14 | /// completion (postfix, keyword, reference, etc). | 14 | /// completion (postfix, keyword, reference, etc). |
15 | #[allow(unused)] | 15 | #[allow(unused)] |
16 | completion_kind: CompletionKind, | 16 | pub(crate) completion_kind: CompletionKind, |
17 | /// Label in the completion pop up which identifies completion. | 17 | /// Label in the completion pop up which identifies completion. |
18 | label: String, | 18 | label: String, |
19 | /// Range of identifier that is being completed. | 19 | /// Range of identifier that is being completed. |
@@ -80,6 +80,9 @@ impl fmt::Debug for CompletionItem { | |||
80 | if self.deprecated { | 80 | if self.deprecated { |
81 | s.field("deprecated", &true); | 81 | s.field("deprecated", &true); |
82 | } | 82 | } |
83 | if self.trigger_call_info { | ||
84 | s.field("trigger_call_info", &true); | ||
85 | } | ||
83 | s.finish() | 86 | s.finish() |
84 | } | 87 | } |
85 | } | 88 | } |
@@ -318,20 +321,3 @@ impl Into<Vec<CompletionItem>> for Completions { | |||
318 | self.buf | 321 | self.buf |
319 | } | 322 | } |
320 | } | 323 | } |
321 | |||
322 | #[cfg(test)] | ||
323 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | ||
324 | use crate::completion::completions; | ||
325 | use crate::mock_analysis::{analysis_and_position, single_file_with_position}; | ||
326 | let (analysis, position) = if code.contains("//-") { | ||
327 | analysis_and_position(code) | ||
328 | } else { | ||
329 | single_file_with_position(code) | ||
330 | }; | ||
331 | let completions = completions(&analysis.db, position).unwrap(); | ||
332 | let completion_items: Vec<CompletionItem> = completions.into(); | ||
333 | let mut kind_completions: Vec<CompletionItem> = | ||
334 | completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); | ||
335 | kind_completions.sort_by_key(|c| c.label.clone()); | ||
336 | kind_completions | ||
337 | } | ||
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index aada4d025..253848602 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -1,6 +1,6 @@ | |||
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 | 2 | ||
3 | use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; | 3 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -9,7 +9,10 @@ use crate::completion::{ | |||
9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::display::{const_label, macro_label, type_label, FunctionSignature}; | 12 | use crate::{ |
13 | display::{const_label, macro_label, type_label, FunctionSignature}, | ||
14 | RootDatabase, | ||
15 | }; | ||
13 | 16 | ||
14 | impl Completions { | 17 | impl Completions { |
15 | pub(crate) fn add_field( | 18 | pub(crate) fn add_field( |
@@ -104,10 +107,7 @@ impl Completions { | |||
104 | }; | 107 | }; |
105 | 108 | ||
106 | // Add `<>` for generic types | 109 | // Add `<>` for generic types |
107 | if ctx.is_path_type | 110 | if ctx.is_path_type && !ctx.has_type_args && ctx.options.add_call_parenthesis { |
108 | && !ctx.has_type_args | ||
109 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
110 | { | ||
111 | let has_non_default_type_params = match resolution { | 111 | let has_non_default_type_params = match resolution { |
112 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), | 112 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), |
113 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), | 113 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), |
@@ -212,21 +212,14 @@ impl Completions { | |||
212 | .detail(function_signature.to_string()); | 212 | .detail(function_signature.to_string()); |
213 | 213 | ||
214 | // If not an import, add parenthesis automatically. | 214 | // If not an import, add parenthesis automatically. |
215 | if ctx.use_item_syntax.is_none() | 215 | if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.options.add_call_parenthesis { |
216 | && !ctx.is_call | ||
217 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
218 | { | ||
219 | tested_by!(inserts_parens_for_function_calls); | 216 | tested_by!(inserts_parens_for_function_calls); |
220 | 217 | ||
221 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { | 218 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { |
222 | (format!("{}()$0", name), format!("{}()", name)) | 219 | (format!("{}()$0", name), format!("{}()", name)) |
223 | } else { | 220 | } else { |
224 | builder = builder.trigger_call_info(); | 221 | builder = builder.trigger_call_info(); |
225 | let snippet = if ctx | 222 | let snippet = if ctx.options.add_call_argument_snippets { |
226 | .db | ||
227 | .feature_flags | ||
228 | .get("completion.insertion.add-argument-snippets") | ||
229 | { | ||
230 | let to_skip = if has_self_param { 1 } else { 0 }; | 223 | let to_skip = if has_self_param { 1 } else { 0 }; |
231 | let function_params_snippet = join( | 224 | let function_params_snippet = join( |
232 | function_signature.parameter_names.iter().skip(to_skip).enumerate().map( | 225 | function_signature.parameter_names.iter().skip(to_skip).enumerate().map( |
@@ -283,8 +276,10 @@ impl Completions { | |||
283 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { | 276 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { |
284 | let is_deprecated = is_deprecated(variant, ctx.db); | 277 | let is_deprecated = is_deprecated(variant, ctx.db); |
285 | let name = variant.name(ctx.db); | 278 | let name = variant.name(ctx.db); |
286 | let detail_types = | 279 | let detail_types = variant |
287 | variant.fields(ctx.db).into_iter().map(|field| (field.name(ctx.db), field.ty(ctx.db))); | 280 | .fields(ctx.db) |
281 | .into_iter() | ||
282 | .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); | ||
288 | let detail = match variant.kind(ctx.db) { | 283 | let detail = match variant.kind(ctx.db) { |
289 | StructKind::Tuple | StructKind::Unit => { | 284 | StructKind::Tuple | StructKind::Unit => { |
290 | join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) | 285 | join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) |
@@ -308,7 +303,7 @@ impl Completions { | |||
308 | } | 303 | } |
309 | } | 304 | } |
310 | 305 | ||
311 | fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool { | 306 | fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool { |
312 | node.attrs(db).by_key("deprecated").exists() | 307 | node.attrs(db).by_key("deprecated").exists() |
313 | } | 308 | } |
314 | 309 | ||
@@ -317,12 +312,22 @@ mod tests { | |||
317 | use insta::assert_debug_snapshot; | 312 | use insta::assert_debug_snapshot; |
318 | use test_utils::covers; | 313 | use test_utils::covers; |
319 | 314 | ||
320 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | 315 | use crate::completion::{ |
316 | test_utils::{do_completion, do_completion_with_options}, | ||
317 | CompletionItem, CompletionKind, CompletionOptions, | ||
318 | }; | ||
321 | 319 | ||
322 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { | 320 | fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { |
323 | do_completion(ra_fixture, CompletionKind::Reference) | 321 | do_completion(ra_fixture, CompletionKind::Reference) |
324 | } | 322 | } |
325 | 323 | ||
324 | fn do_reference_completion_with_options( | ||
325 | ra_fixture: &str, | ||
326 | options: CompletionOptions, | ||
327 | ) -> Vec<CompletionItem> { | ||
328 | do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) | ||
329 | } | ||
330 | |||
326 | #[test] | 331 | #[test] |
327 | fn enum_detail_includes_names_for_record() { | 332 | fn enum_detail_includes_names_for_record() { |
328 | assert_debug_snapshot!( | 333 | assert_debug_snapshot!( |
@@ -510,6 +515,7 @@ mod tests { | |||
510 | kind: Function, | 515 | kind: Function, |
511 | lookup: "with_args", | 516 | lookup: "with_args", |
512 | detail: "fn with_args(x: i32, y: String)", | 517 | detail: "fn with_args(x: i32, y: String)", |
518 | trigger_call_info: true, | ||
513 | }, | 519 | }, |
514 | ] | 520 | ] |
515 | "### | 521 | "### |
@@ -543,7 +549,7 @@ mod tests { | |||
543 | } | 549 | } |
544 | 550 | ||
545 | #[test] | 551 | #[test] |
546 | fn parens_for_method_call() { | 552 | fn arg_snippets_for_method_call() { |
547 | assert_debug_snapshot!( | 553 | assert_debug_snapshot!( |
548 | do_reference_completion( | 554 | do_reference_completion( |
549 | r" | 555 | r" |
@@ -566,6 +572,42 @@ mod tests { | |||
566 | kind: Method, | 572 | kind: Method, |
567 | lookup: "foo", | 573 | lookup: "foo", |
568 | detail: "fn foo(&self, x: i32)", | 574 | detail: "fn foo(&self, x: i32)", |
575 | trigger_call_info: true, | ||
576 | }, | ||
577 | ] | ||
578 | "### | ||
579 | ) | ||
580 | } | ||
581 | |||
582 | #[test] | ||
583 | fn no_arg_snippets_for_method_call() { | ||
584 | assert_debug_snapshot!( | ||
585 | do_reference_completion_with_options( | ||
586 | r" | ||
587 | struct S {} | ||
588 | impl S { | ||
589 | fn foo(&self, x: i32) {} | ||
590 | } | ||
591 | fn bar(s: &S) { | ||
592 | s.f<|> | ||
593 | } | ||
594 | ", | ||
595 | CompletionOptions { | ||
596 | add_call_argument_snippets: false, | ||
597 | .. Default::default() | ||
598 | } | ||
599 | ), | ||
600 | @r###" | ||
601 | [ | ||
602 | CompletionItem { | ||
603 | label: "foo(…)", | ||
604 | source_range: [171; 172), | ||
605 | delete: [171; 172), | ||
606 | insert: "foo($0)", | ||
607 | kind: Method, | ||
608 | lookup: "foo", | ||
609 | detail: "fn foo(&self, x: i32)", | ||
610 | trigger_call_info: true, | ||
569 | }, | 611 | }, |
570 | ] | 612 | ] |
571 | "### | 613 | "### |
@@ -684,6 +726,7 @@ mod tests { | |||
684 | kind: Function, | 726 | kind: Function, |
685 | lookup: "foo", | 727 | lookup: "foo", |
686 | detail: "fn foo(xs: Ve)", | 728 | detail: "fn foo(xs: Ve)", |
729 | trigger_call_info: true, | ||
687 | }, | 730 | }, |
688 | ] | 731 | ] |
689 | "### | 732 | "### |
@@ -713,6 +756,7 @@ mod tests { | |||
713 | kind: Function, | 756 | kind: Function, |
714 | lookup: "foo", | 757 | lookup: "foo", |
715 | detail: "fn foo(xs: Ve)", | 758 | detail: "fn foo(xs: Ve)", |
759 | trigger_call_info: true, | ||
716 | }, | 760 | }, |
717 | ] | 761 | ] |
718 | "### | 762 | "### |
@@ -741,6 +785,7 @@ mod tests { | |||
741 | kind: Function, | 785 | kind: Function, |
742 | lookup: "foo", | 786 | lookup: "foo", |
743 | detail: "fn foo(xs: Ve)", | 787 | detail: "fn foo(xs: Ve)", |
788 | trigger_call_info: true, | ||
744 | }, | 789 | }, |
745 | ] | 790 | ] |
746 | "### | 791 | "### |
@@ -769,6 +814,7 @@ mod tests { | |||
769 | kind: Function, | 814 | kind: Function, |
770 | lookup: "foo", | 815 | lookup: "foo", |
771 | detail: "fn foo(xs: Ve<i128>)", | 816 | detail: "fn foo(xs: Ve<i128>)", |
817 | trigger_call_info: true, | ||
772 | }, | 818 | }, |
773 | ] | 819 | ] |
774 | "### | 820 | "### |
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs new file mode 100644 index 000000000..136857315 --- /dev/null +++ b/crates/ra_ide/src/completion/test_utils.rs | |||
@@ -0,0 +1,29 @@ | |||
1 | //! Runs completion for testing purposes. | ||
2 | |||
3 | use crate::{ | ||
4 | completion::{completion_item::CompletionKind, CompletionOptions}, | ||
5 | mock_analysis::{analysis_and_position, single_file_with_position}, | ||
6 | CompletionItem, | ||
7 | }; | ||
8 | |||
9 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | ||
10 | do_completion_with_options(code, kind, &CompletionOptions::default()) | ||
11 | } | ||
12 | |||
13 | pub(crate) fn do_completion_with_options( | ||
14 | code: &str, | ||
15 | kind: CompletionKind, | ||
16 | options: &CompletionOptions, | ||
17 | ) -> Vec<CompletionItem> { | ||
18 | let (analysis, position) = if code.contains("//-") { | ||
19 | analysis_and_position(code) | ||
20 | } else { | ||
21 | single_file_with_position(code) | ||
22 | }; | ||
23 | let completions = analysis.completions(position, options).unwrap().unwrap(); | ||
24 | let completion_items: Vec<CompletionItem> = completions.into(); | ||
25 | let mut kind_completions: Vec<CompletionItem> = | ||
26 | completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); | ||
27 | kind_completions.sort_by_key(|c| c.label().to_owned()); | ||
28 | kind_completions | ||
29 | } | ||