aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion/complete_fn_param.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/completion/complete_fn_param.rs')
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
new file mode 100644
index 000000000..c1739e47e
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -0,0 +1,102 @@
1use ra_syntax::{
2 algo::visit::{visitor_ctx, VisitorCtx},
3 ast,
4 AstNode,
5};
6use rustc_hash::FxHashMap;
7
8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem};
9
10/// Complete repeated parametes, both name and type. For example, if all
11/// functions in a file have a `spam: &mut Spam` parameter, a completion with
12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
13/// suggested.
14pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) {
15 if !ctx.is_param {
16 return;
17 }
18
19 let mut params = FxHashMap::default();
20 for node in ctx.leaf.ancestors() {
21 let _ = visitor_ctx(&mut params)
22 .visit::<ast::SourceFile, _>(process)
23 .visit::<ast::ItemList, _>(process)
24 .accept(node);
25 }
26 params
27 .into_iter()
28 .filter_map(|(label, (count, param))| {
29 let lookup = param.pat()?.syntax().text().to_string();
30 if count < 2 {
31 None
32 } else {
33 Some((label, lookup))
34 }
35 })
36 .for_each(|(label, lookup)| {
37 CompletionItem::new(CompletionKind::Magic, label)
38 .lookup_by(lookup)
39 .add_to(acc)
40 });
41
42 fn process<'a, N: ast::FnDefOwner>(
43 node: &'a N,
44 params: &mut FxHashMap<String, (u32, &'a ast::Param)>,
45 ) {
46 node.functions()
47 .filter_map(|it| it.param_list())
48 .flat_map(|it| it.params())
49 .for_each(|param| {
50 let text = param.syntax().text().to_string();
51 params.entry(text).or_insert((0, param)).0 += 1;
52 })
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use crate::completion::*;
59
60 fn check_magic_completion(code: &str, expected_completions: &str) {
61 check_completion(code, expected_completions, CompletionKind::Magic);
62 }
63
64 #[test]
65 fn test_param_completion_last_param() {
66 check_magic_completion(
67 r"
68 fn foo(file_id: FileId) {}
69 fn bar(file_id: FileId) {}
70 fn baz(file<|>) {}
71 ",
72 r#"file_id "file_id: FileId""#,
73 );
74 }
75
76 #[test]
77 fn test_param_completion_nth_param() {
78 check_magic_completion(
79 r"
80 fn foo(file_id: FileId) {}
81 fn bar(file_id: FileId) {}
82 fn baz(file<|>, x: i32) {}
83 ",
84 r#"file_id "file_id: FileId""#,
85 );
86 }
87
88 #[test]
89 fn test_param_completion_trait_param() {
90 check_magic_completion(
91 r"
92 pub(crate) trait SourceRoot {
93 pub fn contains(&self, file_id: FileId) -> bool;
94 pub fn module_map(&self) -> &ModuleMap;
95 pub fn lines(&self, file_id: FileId) -> &LineIndex;
96 pub fn syntax(&self, file<|>)
97 }
98 ",
99 r#"file_id "file_id: FileId""#,
100 );
101 }
102}