aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/completion/complete_fn_param.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/completion/complete_fn_param.rs')
-rw-r--r--crates/ra_analysis/src/completion/complete_fn_param.rs103
1 files changed, 103 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/completion/complete_fn_param.rs b/crates/ra_analysis/src/completion/complete_fn_param.rs
new file mode 100644
index 000000000..6a6213e67
--- /dev/null
+++ b/crates/ra_analysis/src/completion/complete_fn_param.rs
@@ -0,0 +1,103 @@
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(label)
38 .lookup_by(lookup)
39 .kind(CompletionKind::Magic)
40 .add_to(acc)
41 });
42
43 fn process<'a, N: ast::FnDefOwner<'a>>(
44 node: N,
45 params: &mut FxHashMap<String, (u32, ast::Param<'a>)>,
46 ) {
47 node.functions()
48 .filter_map(|it| it.param_list())
49 .flat_map(|it| it.params())
50 .for_each(|param| {
51 let text = param.syntax().text().to_string();
52 params.entry(text).or_insert((0, param)).0 += 1;
53 })
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use crate::completion::*;
60
61 fn check_magic_completion(code: &str, expected_completions: &str) {
62 check_completion(code, expected_completions, CompletionKind::Magic);
63 }
64
65 #[test]
66 fn test_param_completion_last_param() {
67 check_magic_completion(
68 r"
69 fn foo(file_id: FileId) {}
70 fn bar(file_id: FileId) {}
71 fn baz(file<|>) {}
72 ",
73 r#"file_id "file_id: FileId""#,
74 );
75 }
76
77 #[test]
78 fn test_param_completion_nth_param() {
79 check_magic_completion(
80 r"
81 fn foo(file_id: FileId) {}
82 fn bar(file_id: FileId) {}
83 fn baz(file<|>, x: i32) {}
84 ",
85 r#"file_id "file_id: FileId""#,
86 );
87 }
88
89 #[test]
90 fn test_param_completion_trait_param() {
91 check_magic_completion(
92 r"
93 pub(crate) trait SourceRoot {
94 pub fn contains(&self, file_id: FileId) -> bool;
95 pub fn module_map(&self) -> &ModuleMap;
96 pub fn lines(&self, file_id: FileId) -> &LineIndex;
97 pub fn syntax(&self, file<|>)
98 }
99 ",
100 r#"file_id "file_id: FileId""#,
101 );
102 }
103}