]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/fn_param.rs
Replace some String usages with SmolStr in completions
[rust.git] / crates / ide_completion / src / completions / fn_param.rs
1 //! See [`complete_fn_param`].
2
3 use rustc_hash::FxHashMap;
4 use syntax::{
5     ast::{self, HasModuleItem},
6     match_ast, AstNode,
7 };
8
9 use crate::{
10     context::{ParamKind, PatternContext},
11     CompletionContext, CompletionItem, CompletionItemKind, Completions,
12 };
13
14 /// Complete repeated parameters, both name and type. For example, if all
15 /// functions in a file have a `spam: &mut Spam` parameter, a completion with
16 /// `spam: &mut Spam` insert text/label and `spam` lookup string will be
17 /// suggested.
18 pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
19     if !matches!(ctx.pattern_ctx, Some(PatternContext { is_param: Some(ParamKind::Function), .. }))
20     {
21         return None;
22     }
23
24     let mut params = FxHashMap::default();
25
26     let me = ctx.token.ancestors().find_map(ast::Fn::cast);
27     let mut process_fn = |func: ast::Fn| {
28         if Some(&func) == me.as_ref() {
29             return;
30         }
31         func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
32             if let Some(pat) = param.pat() {
33                 // FIXME: We should be able to turn these into SmolStr without having to allocate a String
34                 let text = param.syntax().text().to_string();
35                 let lookup = pat.syntax().text().to_string();
36                 params.entry(text).or_insert(lookup);
37             }
38         });
39     };
40
41     for node in ctx.token.ancestors() {
42         match_ast! {
43             match node {
44                 ast::SourceFile(it) => it.items().filter_map(|item| match item {
45                     ast::Item::Fn(it) => Some(it),
46                     _ => None,
47                 }).for_each(&mut process_fn),
48                 ast::ItemList(it) => it.items().filter_map(|item| match item {
49                     ast::Item::Fn(it) => Some(it),
50                     _ => None,
51                 }).for_each(&mut process_fn),
52                 ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item {
53                     ast::AssocItem::Fn(it) => Some(it),
54                     _ => None,
55                 }).for_each(&mut process_fn),
56                 _ => continue,
57             }
58         };
59     }
60
61     let self_completion_items = ["self", "&self", "mut self", "&mut self"];
62     if ctx.impl_def.is_some() && me?.param_list()?.params().next().is_none() {
63         self_completion_items.into_iter().for_each(|self_item| {
64             add_new_item_to_acc(ctx, acc, self_item.to_string(), self_item.to_string())
65         });
66     }
67
68     params.into_iter().for_each(|(label, lookup)| add_new_item_to_acc(ctx, acc, label, lookup));
69
70     Some(())
71 }
72
73 fn add_new_item_to_acc(
74     ctx: &CompletionContext,
75     acc: &mut Completions,
76     label: String,
77     lookup: String,
78 ) {
79     let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
80     item.lookup_by(lookup);
81     item.add_to(acc)
82 }