aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/render/function.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/render/function.rs')
-rw-r--r--crates/completion/src/render/function.rs341
1 files changed, 0 insertions, 341 deletions
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
deleted file mode 100644
index f5b0ce3e3..000000000
--- a/crates/completion/src/render/function.rs
+++ /dev/null
@@ -1,341 +0,0 @@
1//! Renderer for function calls.
2
3use hir::{HasSource, Type};
4use syntax::{ast::Fn, display::function_declaration};
5use test_utils::mark;
6
7use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, RenderContext},
10};
11
12pub(crate) fn render_fn<'a>(
13 ctx: RenderContext<'a>,
14 import_to_add: Option<ImportEdit>,
15 local_name: Option<String>,
16 fn_: hir::Function,
17) -> Option<CompletionItem> {
18 let _p = profile::span("render_fn");
19 Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
20}
21
22#[derive(Debug)]
23struct FunctionRender<'a> {
24 ctx: RenderContext<'a>,
25 name: String,
26 func: hir::Function,
27 ast_node: Fn,
28}
29
30impl<'a> FunctionRender<'a> {
31 fn new(
32 ctx: RenderContext<'a>,
33 local_name: Option<String>,
34 fn_: hir::Function,
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;
38
39 Some(FunctionRender { ctx, name, func: fn_, ast_node })
40 }
41
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())
45 .kind(self.kind())
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)
51 .build()
52 }
53
54 fn detail(&self) -> String {
55 function_declaration(&self.ast_node)
56 }
57
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);
64 }
65 }
66 }
67 arg.to_string()
68 }
69
70 fn params(&self) -> Params {
71 let ast_params = match self.ast_node.param_list() {
72 Some(it) => it,
73 None => return Params::Named(Vec::new()),
74 };
75
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()
79 } else {
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()));
83 }
84 self.func.assoc_fn_params(self.ctx.db())
85 };
86 params_pats
87 .extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string())));
88
89 let params = params_pats
90 .into_iter()
91 .zip(params_ty)
92 .flat_map(|(pat, param_ty)| {
93 let pat = pat?;
94 let name = pat;
95 let arg = name.trim_start_matches("mut ").trim_start_matches('_');
96 Some(self.add_arg(arg, param_ty.ty()))
97 })
98 .collect();
99 Params::Named(params)
100 }
101
102 fn kind(&self) -> CompletionItemKind {
103 if self.func.self_param(self.ctx.db()).is_some() {
104 CompletionItemKind::Method
105 } else {
106 CompletionItemKind::Function
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use test_utils::mark;
114
115 use crate::{
116 test_utils::{check_edit, check_edit_with_config, TEST_CONFIG},
117 CompletionConfig,
118 };
119
120 #[test]
121 fn inserts_parens_for_function_calls() {
122 mark::check!(inserts_parens_for_function_calls);
123 check_edit(
124 "no_args",
125 r#"
126fn no_args() {}
127fn main() { no_$0 }
128"#,
129 r#"
130fn no_args() {}
131fn main() { no_args()$0 }
132"#,
133 );
134
135 check_edit(
136 "with_args",
137 r#"
138fn with_args(x: i32, y: String) {}
139fn main() { with_$0 }
140"#,
141 r#"
142fn with_args(x: i32, y: String) {}
143fn main() { with_args(${1:x}, ${2:y})$0 }
144"#,
145 );
146
147 check_edit(
148 "foo",
149 r#"
150struct S;
151impl S {
152 fn foo(&self) {}
153}
154fn bar(s: &S) { s.f$0 }
155"#,
156 r#"
157struct S;
158impl S {
159 fn foo(&self) {}
160}
161fn bar(s: &S) { s.foo()$0 }
162"#,
163 );
164
165 check_edit(
166 "foo",
167 r#"
168struct S {}
169impl S {
170 fn foo(&self, x: i32) {}
171}
172fn bar(s: &S) {
173 s.f$0
174}
175"#,
176 r#"
177struct S {}
178impl S {
179 fn foo(&self, x: i32) {}
180}
181fn bar(s: &S) {
182 s.foo(${1:x})$0
183}
184"#,
185 );
186 }
187
188 #[test]
189 fn parens_for_method_call_as_assoc_fn() {
190 mark::check!(parens_for_method_call_as_assoc_fn);
191 check_edit(
192 "foo",
193 r#"
194struct S;
195impl S {
196 fn foo(&self) {}
197}
198fn main() { S::f$0 }
199"#,
200 r#"
201struct S;
202impl S {
203 fn foo(&self) {}
204}
205fn main() { S::foo(${1:&self})$0 }
206"#,
207 );
208 }
209
210 #[test]
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 },
215 "with_args",
216 r#"
217fn with_args(x: i32, y: String) {}
218fn main() { with_$0 }
219"#,
220 r#"
221fn with_args(x: i32, y: String) {}
222fn main() { with_args($0) }
223"#,
224 );
225 }
226
227 #[test]
228 fn strips_underscores_from_args() {
229 check_edit(
230 "foo",
231 r#"
232fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
233fn main() { f$0 }
234"#,
235 r#"
236fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
237fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
238"#,
239 );
240 }
241
242 #[test]
243 fn insert_ref_when_matching_local_in_scope() {
244 check_edit(
245 "ref_arg",
246 r#"
247struct Foo {}
248fn ref_arg(x: &Foo) {}
249fn main() {
250 let x = Foo {};
251 ref_ar$0
252}
253"#,
254 r#"
255struct Foo {}
256fn ref_arg(x: &Foo) {}
257fn main() {
258 let x = Foo {};
259 ref_arg(${1:&x})$0
260}
261"#,
262 );
263 }
264
265 #[test]
266 fn insert_mut_ref_when_matching_local_in_scope() {
267 check_edit(
268 "ref_arg",
269 r#"
270struct Foo {}
271fn ref_arg(x: &mut Foo) {}
272fn main() {
273 let x = Foo {};
274 ref_ar$0
275}
276"#,
277 r#"
278struct Foo {}
279fn ref_arg(x: &mut Foo) {}
280fn main() {
281 let x = Foo {};
282 ref_arg(${1:&mut x})$0
283}
284"#,
285 );
286 }
287
288 #[test]
289 fn insert_ref_when_matching_local_in_scope_for_method() {
290 check_edit(
291 "apply_foo",
292 r#"
293struct Foo {}
294struct Bar {}
295impl Bar {
296 fn apply_foo(&self, x: &Foo) {}
297}
298
299fn main() {
300 let x = Foo {};
301 let y = Bar {};
302 y.$0
303}
304"#,
305 r#"
306struct Foo {}
307struct Bar {}
308impl Bar {
309 fn apply_foo(&self, x: &Foo) {}
310}
311
312fn main() {
313 let x = Foo {};
314 let y = Bar {};
315 y.apply_foo(${1:&x})$0
316}
317"#,
318 );
319 }
320
321 #[test]
322 fn trim_mut_keyword_in_func_completion() {
323 check_edit(
324 "take_mutably",
325 r#"
326fn take_mutably(mut x: &i32) {}
327
328fn main() {
329 take_m$0
330}
331"#,
332 r#"
333fn take_mutably(mut x: &i32) {}
334
335fn main() {
336 take_mutably(${1:x})$0
337}
338"#,
339 );
340 }
341}