diff options
Diffstat (limited to 'crates/ra_ide/src/completion/complete_fn_param.rs')
-rw-r--r-- | crates/ra_ide/src/completion/complete_fn_param.rs | 161 |
1 files changed, 79 insertions, 82 deletions
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs index f5573ddf7..406334257 100644 --- a/crates/ra_ide/src/completion/complete_fn_param.rs +++ b/crates/ra_ide/src/completion/complete_fn_param.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! See `complete_fn_param`. |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, ModuleItemOwner}, | 4 | ast::{self, ModuleItemOwner}, |
@@ -18,35 +18,47 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
18 | } | 18 | } |
19 | 19 | ||
20 | let mut params = FxHashMap::default(); | 20 | let mut params = FxHashMap::default(); |
21 | |||
22 | let me = ctx.token.ancestors().find_map(ast::Fn::cast); | ||
23 | let mut process_fn = |func: ast::Fn| { | ||
24 | if Some(&func) == me.as_ref() { | ||
25 | return; | ||
26 | } | ||
27 | func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { | ||
28 | let text = param.syntax().text().to_string(); | ||
29 | params.entry(text).or_insert(param); | ||
30 | }) | ||
31 | }; | ||
32 | |||
21 | for node in ctx.token.parent().ancestors() { | 33 | for node in ctx.token.parent().ancestors() { |
22 | let items = match_ast! { | 34 | match_ast! { |
23 | match node { | 35 | match node { |
24 | ast::SourceFile(it) => it.items(), | 36 | ast::SourceFile(it) => it.items().filter_map(|item| match item { |
25 | ast::ItemList(it) => it.items(), | 37 | ast::Item::Fn(it) => Some(it), |
38 | _ => None, | ||
39 | }).for_each(&mut process_fn), | ||
40 | ast::ItemList(it) => it.items().filter_map(|item| match item { | ||
41 | ast::Item::Fn(it) => Some(it), | ||
42 | _ => None, | ||
43 | }).for_each(&mut process_fn), | ||
44 | ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item { | ||
45 | ast::AssocItem::Fn(it) => Some(it), | ||
46 | _ => None, | ||
47 | }).for_each(&mut process_fn), | ||
26 | _ => continue, | 48 | _ => continue, |
27 | } | 49 | } |
28 | }; | 50 | }; |
29 | for item in items { | ||
30 | if let ast::ModuleItem::FnDef(func) = item { | ||
31 | func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { | ||
32 | let text = param.syntax().text().to_string(); | ||
33 | params.entry(text).or_insert((0, param)).0 += 1; | ||
34 | }) | ||
35 | } | ||
36 | } | ||
37 | } | 51 | } |
52 | |||
38 | params | 53 | params |
39 | .into_iter() | 54 | .into_iter() |
40 | .filter_map(|(label, (count, param))| { | 55 | .filter_map(|(label, param)| { |
41 | let lookup = param.pat()?.syntax().text().to_string(); | 56 | let lookup = param.pat()?.syntax().text().to_string(); |
42 | if count < 2 { | 57 | Some((label, lookup)) |
43 | None | ||
44 | } else { | ||
45 | Some((label, lookup)) | ||
46 | } | ||
47 | }) | 58 | }) |
48 | .for_each(|(label, lookup)| { | 59 | .for_each(|(label, lookup)| { |
49 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) | 60 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) |
61 | .kind(crate::CompletionItemKind::Binding) | ||
50 | .lookup_by(lookup) | 62 | .lookup_by(lookup) |
51 | .add_to(acc) | 63 | .add_to(acc) |
52 | }); | 64 | }); |
@@ -54,85 +66,70 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
54 | 66 | ||
55 | #[cfg(test)] | 67 | #[cfg(test)] |
56 | mod tests { | 68 | mod tests { |
57 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 69 | use expect::{expect, Expect}; |
58 | use insta::assert_debug_snapshot; | 70 | |
71 | use crate::completion::{test_utils::completion_list, CompletionKind}; | ||
59 | 72 | ||
60 | fn do_magic_completion(code: &str) -> Vec<CompletionItem> { | 73 | fn check(ra_fixture: &str, expect: Expect) { |
61 | do_completion(code, CompletionKind::Magic) | 74 | let actual = completion_list(ra_fixture, CompletionKind::Magic); |
75 | expect.assert_eq(&actual); | ||
62 | } | 76 | } |
63 | 77 | ||
64 | #[test] | 78 | #[test] |
65 | fn test_param_completion_last_param() { | 79 | fn test_param_completion_last_param() { |
66 | assert_debug_snapshot!( | 80 | check( |
67 | do_magic_completion( | 81 | r#" |
68 | r" | 82 | fn foo(file_id: FileId) {} |
69 | fn foo(file_id: FileId) {} | 83 | fn bar(file_id: FileId) {} |
70 | fn bar(file_id: FileId) {} | 84 | fn baz(file<|>) {} |
71 | fn baz(file<|>) {} | 85 | "#, |
72 | ", | 86 | expect![[r#" |
73 | ), | 87 | bn file_id: FileId |
74 | @r###" | 88 | "#]], |
75 | [ | ||
76 | CompletionItem { | ||
77 | label: "file_id: FileId", | ||
78 | source_range: 61..65, | ||
79 | delete: 61..65, | ||
80 | insert: "file_id: FileId", | ||
81 | lookup: "file_id", | ||
82 | }, | ||
83 | ] | ||
84 | "### | ||
85 | ); | 89 | ); |
86 | } | 90 | } |
87 | 91 | ||
88 | #[test] | 92 | #[test] |
89 | fn test_param_completion_nth_param() { | 93 | fn test_param_completion_nth_param() { |
90 | assert_debug_snapshot!( | 94 | check( |
91 | do_magic_completion( | 95 | r#" |
92 | r" | 96 | fn foo(file_id: FileId) {} |
93 | fn foo(file_id: FileId) {} | 97 | fn baz(file<|>, x: i32) {} |
94 | fn bar(file_id: FileId) {} | 98 | "#, |
95 | fn baz(file<|>, x: i32) {} | 99 | expect![[r#" |
96 | ", | 100 | bn file_id: FileId |
97 | ), | 101 | "#]], |
98 | @r###" | ||
99 | [ | ||
100 | CompletionItem { | ||
101 | label: "file_id: FileId", | ||
102 | source_range: 61..65, | ||
103 | delete: 61..65, | ||
104 | insert: "file_id: FileId", | ||
105 | lookup: "file_id", | ||
106 | }, | ||
107 | ] | ||
108 | "### | ||
109 | ); | 102 | ); |
110 | } | 103 | } |
111 | 104 | ||
112 | #[test] | 105 | #[test] |
113 | fn test_param_completion_trait_param() { | 106 | fn test_param_completion_trait_param() { |
114 | assert_debug_snapshot!( | 107 | check( |
115 | do_magic_completion( | 108 | r#" |
116 | r" | 109 | pub(crate) trait SourceRoot { |
117 | pub(crate) trait SourceRoot { | 110 | pub fn contains(&self, file_id: FileId) -> bool; |
118 | pub fn contains(&self, file_id: FileId) -> bool; | 111 | pub fn module_map(&self) -> &ModuleMap; |
119 | pub fn module_map(&self) -> &ModuleMap; | 112 | pub fn lines(&self, file_id: FileId) -> &LineIndex; |
120 | pub fn lines(&self, file_id: FileId) -> &LineIndex; | 113 | pub fn syntax(&self, file<|>) |
121 | pub fn syntax(&self, file<|>) | 114 | } |
122 | } | 115 | "#, |
123 | ", | 116 | expect![[r#" |
124 | ), | 117 | bn file_id: FileId |
125 | @r###" | 118 | "#]], |
126 | [ | ||
127 | CompletionItem { | ||
128 | label: "file_id: FileId", | ||
129 | source_range: 208..212, | ||
130 | delete: 208..212, | ||
131 | insert: "file_id: FileId", | ||
132 | lookup: "file_id", | ||
133 | }, | ||
134 | ] | ||
135 | "### | ||
136 | ); | 119 | ); |
137 | } | 120 | } |
121 | |||
122 | #[test] | ||
123 | fn completes_param_in_inner_function() { | ||
124 | check( | ||
125 | r#" | ||
126 | fn outer(text: String) { | ||
127 | fn inner(<|>) | ||
128 | } | ||
129 | "#, | ||
130 | expect![[r#" | ||
131 | bn text: String | ||
132 | "#]], | ||
133 | ) | ||
134 | } | ||
138 | } | 135 | } |