1 //! Renderer for function calls.
3 use hir::{HasSource, Type};
4 use syntax::{ast::Fn, display::function_declaration};
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, RenderContext},
12 pub(crate) fn render_fn<'a>(
13 ctx: RenderContext<'a>,
14 import_to_add: Option<ImportEdit>,
15 local_name: Option<String>,
17 ) -> Option<CompletionItem> {
18 let _p = profile::span("render_fn");
19 Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
23 struct FunctionRender<'a> {
24 ctx: RenderContext<'a>,
30 impl<'a> FunctionRender<'a> {
32 ctx: RenderContext<'a>,
33 local_name: Option<String>,
35 ) -> Option<FunctionRender<'a>> {
36 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string());
37 let ast_node = fn_.source(ctx.db())?.value;
39 Some(FunctionRender { ctx, name, func: fn_, ast_node })
42 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
43 let params = self.params();
44 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
46 .set_documentation(self.ctx.docs(self.func))
47 .set_deprecated(self.ctx.is_deprecated(self.func))
48 .detail(self.detail())
49 .add_call_parens(self.ctx.completion, self.name, params)
50 .add_import(import_to_add)
54 fn detail(&self) -> String {
55 function_declaration(&self.ast_node)
58 fn add_arg(&self, arg: &str, ty: &Type) -> String {
59 if let Some(derefed_ty) = ty.remove_ref() {
60 for (name, local) in self.ctx.completion.locals.iter() {
61 if name == arg && local.ty(self.ctx.db()) == derefed_ty {
62 let mutability = if ty.is_mutable_reference() { "&mut " } else { "&" };
63 return format!("{}{}", mutability, arg);
70 fn params(&self) -> Params {
71 let ast_params = match self.ast_node.param_list() {
73 None => return Params::Named(Vec::new()),
76 let mut params_pats = Vec::new();
77 let params_ty = if self.ctx.completion.dot_receiver.is_some() {
78 self.func.method_params(self.ctx.db()).unwrap_or_default()
80 if let Some(s) = ast_params.self_param() {
81 mark::hit!(parens_for_method_call_as_assoc_fn);
82 params_pats.push(Some(s.to_string()));
84 self.func.assoc_fn_params(self.ctx.db())
87 .extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string())));
89 let params = params_pats
92 .flat_map(|(pat, param_ty)| {
95 let arg = name.trim_start_matches("mut ").trim_start_matches('_');
96 Some(self.add_arg(arg, param_ty.ty()))
102 fn kind(&self) -> CompletionItemKind {
103 if self.func.self_param(self.ctx.db()).is_some() {
104 CompletionItemKind::Method
106 CompletionItemKind::Function
113 use test_utils::mark;
116 test_utils::{check_edit, check_edit_with_config, TEST_CONFIG},
121 fn inserts_parens_for_function_calls() {
122 mark::check!(inserts_parens_for_function_calls);
131 fn main() { no_args()$0 }
138 fn with_args(x: i32, y: String) {}
139 fn main() { with_<|> }
142 fn with_args(x: i32, y: String) {}
143 fn main() { with_args(${1:x}, ${2:y})$0 }
154 fn bar(s: &S) { s.f<|> }
161 fn bar(s: &S) { s.foo()$0 }
170 fn foo(&self, x: i32) {}
179 fn foo(&self, x: i32) {}
189 fn parens_for_method_call_as_assoc_fn() {
190 mark::check!(parens_for_method_call_as_assoc_fn);
198 fn main() { S::f<|> }
205 fn main() { S::foo(${1:&self})$0 }
211 fn suppress_arg_snippets() {
212 mark::check!(suppress_arg_snippets);
213 check_edit_with_config(
214 CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG },
217 fn with_args(x: i32, y: String) {}
218 fn main() { with_<|> }
221 fn with_args(x: i32, y: String) {}
222 fn main() { with_args($0) }
228 fn strips_underscores_from_args() {
232 fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
236 fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
237 fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
243 fn insert_ref_when_matching_local_in_scope() {
248 fn ref_arg(x: &Foo) {}
256 fn ref_arg(x: &Foo) {}
266 fn insert_mut_ref_when_matching_local_in_scope() {
271 fn ref_arg(x: &mut Foo) {}
279 fn ref_arg(x: &mut Foo) {}
282 ref_arg(${1:&mut x})$0
289 fn insert_ref_when_matching_local_in_scope_for_method() {
296 fn apply_foo(&self, x: &Foo) {}
309 fn apply_foo(&self, x: &Foo) {}
315 y.apply_foo(${1:&x})$0
322 fn trim_mut_keyword_in_func_completion() {
326 fn take_mutably(mut x: &i32) {}
333 fn take_mutably(mut x: &i32) {}
336 take_mutably(${1:x})$0