diff options
Diffstat (limited to 'crates/completion/src/render/function.rs')
-rw-r--r-- | crates/completion/src/render/function.rs | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs new file mode 100644 index 000000000..4fa6eafd7 --- /dev/null +++ b/crates/completion/src/render/function.rs | |||
@@ -0,0 +1,303 @@ | |||
1 | //! Renderer for function calls. | ||
2 | |||
3 | use hir::{HasSource, Type}; | ||
4 | use syntax::{ast::Fn, display::function_declaration}; | ||
5 | |||
6 | use crate::{ | ||
7 | item::{CompletionItem, CompletionItemKind, CompletionKind}, | ||
8 | render::{builder_ext::Params, RenderContext}, | ||
9 | }; | ||
10 | |||
11 | pub(crate) fn render_fn<'a>( | ||
12 | ctx: RenderContext<'a>, | ||
13 | local_name: Option<String>, | ||
14 | fn_: hir::Function, | ||
15 | ) -> CompletionItem { | ||
16 | FunctionRender::new(ctx, local_name, fn_).render() | ||
17 | } | ||
18 | |||
19 | #[derive(Debug)] | ||
20 | struct FunctionRender<'a> { | ||
21 | ctx: RenderContext<'a>, | ||
22 | name: String, | ||
23 | fn_: hir::Function, | ||
24 | ast_node: Fn, | ||
25 | } | ||
26 | |||
27 | impl<'a> FunctionRender<'a> { | ||
28 | fn new( | ||
29 | ctx: RenderContext<'a>, | ||
30 | local_name: Option<String>, | ||
31 | fn_: hir::Function, | ||
32 | ) -> FunctionRender<'a> { | ||
33 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); | ||
34 | let ast_node = fn_.source(ctx.db()).value; | ||
35 | |||
36 | FunctionRender { ctx, name, fn_, ast_node } | ||
37 | } | ||
38 | |||
39 | fn render(self) -> CompletionItem { | ||
40 | let params = self.params(); | ||
41 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | ||
42 | .kind(self.kind()) | ||
43 | .set_documentation(self.ctx.docs(self.fn_)) | ||
44 | .set_deprecated(self.ctx.is_deprecated(self.fn_)) | ||
45 | .detail(self.detail()) | ||
46 | .add_call_parens(self.ctx.completion, self.name, params) | ||
47 | .build() | ||
48 | } | ||
49 | |||
50 | fn detail(&self) -> String { | ||
51 | function_declaration(&self.ast_node) | ||
52 | } | ||
53 | |||
54 | fn add_arg(&self, arg: &str, ty: &Type) -> String { | ||
55 | if let Some(derefed_ty) = ty.remove_ref() { | ||
56 | for (name, local) in self.ctx.completion.locals.iter() { | ||
57 | if name == arg && local.ty(self.ctx.db()) == derefed_ty { | ||
58 | let mutability = if ty.is_mutable_reference() { "&mut " } else { "&" }; | ||
59 | return format!("{}{}", mutability, arg); | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | arg.to_string() | ||
64 | } | ||
65 | |||
66 | fn params(&self) -> Params { | ||
67 | let params_ty = self.fn_.params(self.ctx.db()); | ||
68 | let params = self | ||
69 | .ast_node | ||
70 | .param_list() | ||
71 | .into_iter() | ||
72 | .flat_map(|it| it.params()) | ||
73 | .zip(params_ty) | ||
74 | .flat_map(|(it, param_ty)| { | ||
75 | if let Some(pat) = it.pat() { | ||
76 | let name = pat.to_string(); | ||
77 | let arg = name.trim_start_matches("mut ").trim_start_matches('_'); | ||
78 | return Some(self.add_arg(arg, param_ty.ty())); | ||
79 | } | ||
80 | None | ||
81 | }) | ||
82 | .collect(); | ||
83 | Params::Named(params) | ||
84 | } | ||
85 | |||
86 | fn kind(&self) -> CompletionItemKind { | ||
87 | if self.fn_.self_param(self.ctx.db()).is_some() { | ||
88 | CompletionItemKind::Method | ||
89 | } else { | ||
90 | CompletionItemKind::Function | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | #[cfg(test)] | ||
96 | mod tests { | ||
97 | use test_utils::mark; | ||
98 | |||
99 | use crate::{ | ||
100 | test_utils::{check_edit, check_edit_with_config}, | ||
101 | CompletionConfig, | ||
102 | }; | ||
103 | |||
104 | #[test] | ||
105 | fn inserts_parens_for_function_calls() { | ||
106 | mark::check!(inserts_parens_for_function_calls); | ||
107 | check_edit( | ||
108 | "no_args", | ||
109 | r#" | ||
110 | fn no_args() {} | ||
111 | fn main() { no_<|> } | ||
112 | "#, | ||
113 | r#" | ||
114 | fn no_args() {} | ||
115 | fn main() { no_args()$0 } | ||
116 | "#, | ||
117 | ); | ||
118 | |||
119 | check_edit( | ||
120 | "with_args", | ||
121 | r#" | ||
122 | fn with_args(x: i32, y: String) {} | ||
123 | fn main() { with_<|> } | ||
124 | "#, | ||
125 | r#" | ||
126 | fn with_args(x: i32, y: String) {} | ||
127 | fn main() { with_args(${1:x}, ${2:y})$0 } | ||
128 | "#, | ||
129 | ); | ||
130 | |||
131 | check_edit( | ||
132 | "foo", | ||
133 | r#" | ||
134 | struct S; | ||
135 | impl S { | ||
136 | fn foo(&self) {} | ||
137 | } | ||
138 | fn bar(s: &S) { s.f<|> } | ||
139 | "#, | ||
140 | r#" | ||
141 | struct S; | ||
142 | impl S { | ||
143 | fn foo(&self) {} | ||
144 | } | ||
145 | fn bar(s: &S) { s.foo()$0 } | ||
146 | "#, | ||
147 | ); | ||
148 | |||
149 | check_edit( | ||
150 | "foo", | ||
151 | r#" | ||
152 | struct S {} | ||
153 | impl S { | ||
154 | fn foo(&self, x: i32) {} | ||
155 | } | ||
156 | fn bar(s: &S) { | ||
157 | s.f<|> | ||
158 | } | ||
159 | "#, | ||
160 | r#" | ||
161 | struct S {} | ||
162 | impl S { | ||
163 | fn foo(&self, x: i32) {} | ||
164 | } | ||
165 | fn bar(s: &S) { | ||
166 | s.foo(${1:x})$0 | ||
167 | } | ||
168 | "#, | ||
169 | ); | ||
170 | } | ||
171 | |||
172 | #[test] | ||
173 | fn suppress_arg_snippets() { | ||
174 | mark::check!(suppress_arg_snippets); | ||
175 | check_edit_with_config( | ||
176 | CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() }, | ||
177 | "with_args", | ||
178 | r#" | ||
179 | fn with_args(x: i32, y: String) {} | ||
180 | fn main() { with_<|> } | ||
181 | "#, | ||
182 | r#" | ||
183 | fn with_args(x: i32, y: String) {} | ||
184 | fn main() { with_args($0) } | ||
185 | "#, | ||
186 | ); | ||
187 | } | ||
188 | |||
189 | #[test] | ||
190 | fn strips_underscores_from_args() { | ||
191 | check_edit( | ||
192 | "foo", | ||
193 | r#" | ||
194 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | ||
195 | fn main() { f<|> } | ||
196 | "#, | ||
197 | r#" | ||
198 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | ||
199 | fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } | ||
200 | "#, | ||
201 | ); | ||
202 | } | ||
203 | |||
204 | #[test] | ||
205 | fn insert_ref_when_matching_local_in_scope() { | ||
206 | check_edit( | ||
207 | "ref_arg", | ||
208 | r#" | ||
209 | struct Foo {} | ||
210 | fn ref_arg(x: &Foo) {} | ||
211 | fn main() { | ||
212 | let x = Foo {}; | ||
213 | ref_ar<|> | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | struct Foo {} | ||
218 | fn ref_arg(x: &Foo) {} | ||
219 | fn main() { | ||
220 | let x = Foo {}; | ||
221 | ref_arg(${1:&x})$0 | ||
222 | } | ||
223 | "#, | ||
224 | ); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn insert_mut_ref_when_matching_local_in_scope() { | ||
229 | check_edit( | ||
230 | "ref_arg", | ||
231 | r#" | ||
232 | struct Foo {} | ||
233 | fn ref_arg(x: &mut Foo) {} | ||
234 | fn main() { | ||
235 | let x = Foo {}; | ||
236 | ref_ar<|> | ||
237 | } | ||
238 | "#, | ||
239 | r#" | ||
240 | struct Foo {} | ||
241 | fn ref_arg(x: &mut Foo) {} | ||
242 | fn main() { | ||
243 | let x = Foo {}; | ||
244 | ref_arg(${1:&mut x})$0 | ||
245 | } | ||
246 | "#, | ||
247 | ); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn insert_ref_when_matching_local_in_scope_for_method() { | ||
252 | check_edit( | ||
253 | "apply_foo", | ||
254 | r#" | ||
255 | struct Foo {} | ||
256 | struct Bar {} | ||
257 | impl Bar { | ||
258 | fn apply_foo(&self, x: &Foo) {} | ||
259 | } | ||
260 | |||
261 | fn main() { | ||
262 | let x = Foo {}; | ||
263 | let y = Bar {}; | ||
264 | y.<|> | ||
265 | } | ||
266 | "#, | ||
267 | r#" | ||
268 | struct Foo {} | ||
269 | struct Bar {} | ||
270 | impl Bar { | ||
271 | fn apply_foo(&self, x: &Foo) {} | ||
272 | } | ||
273 | |||
274 | fn main() { | ||
275 | let x = Foo {}; | ||
276 | let y = Bar {}; | ||
277 | y.apply_foo(${1:&x})$0 | ||
278 | } | ||
279 | "#, | ||
280 | ); | ||
281 | } | ||
282 | |||
283 | #[test] | ||
284 | fn trim_mut_keyword_in_func_completion() { | ||
285 | check_edit( | ||
286 | "take_mutably", | ||
287 | r#" | ||
288 | fn take_mutably(mut x: &i32) {} | ||
289 | |||
290 | fn main() { | ||
291 | take_m<|> | ||
292 | } | ||
293 | "#, | ||
294 | r#" | ||
295 | fn take_mutably(mut x: &i32) {} | ||
296 | |||
297 | fn main() { | ||
298 | take_mutably(${1:x})$0 | ||
299 | } | ||
300 | "#, | ||
301 | ); | ||
302 | } | ||
303 | } | ||