aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/complete_fn_param.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/complete_fn_param.rs')
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs161
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
3use ra_syntax::{ 3use 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)]
56mod tests { 68mod 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" 82fn foo(file_id: FileId) {}
69 fn foo(file_id: FileId) {} 83fn bar(file_id: FileId) {}
70 fn bar(file_id: FileId) {} 84fn 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" 96fn foo(file_id: FileId) {}
93 fn foo(file_id: FileId) {} 97fn 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" 109pub(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#"
126fn outer(text: String) {
127 fn inner(<|>)
128}
129"#,
130 expect![[r#"
131 bn text: String
132 "#]],
133 )
134 }
138} 135}