]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/generate_function.rs
Merge #9970
[rust.git] / crates / ide_assists / src / handlers / generate_function.rs
1 use hir::{HasSource, HirDisplay, Module, TypeInfo};
2 use ide_db::{base_db::FileId, helpers::SnippetCap};
3 use rustc_hash::{FxHashMap, FxHashSet};
4 use stdx::to_lower_snake_case;
5 use syntax::{
6     ast::{
7         self,
8         edit::{AstNodeEdit, IndentLevel},
9         make, ArgListOwner, AstNode, CallExpr, ModuleItemOwner,
10     },
11     SyntaxKind, SyntaxNode, TextRange, TextSize,
12 };
13
14 use crate::{
15     utils::useless_type_special_case,
16     utils::{find_struct_impl, render_snippet, Cursor},
17     AssistContext, AssistId, AssistKind, Assists,
18 };
19
20 // Assist: generate_function
21 //
22 // Adds a stub function with a signature matching the function under the cursor.
23 //
24 // ```
25 // struct Baz;
26 // fn baz() -> Baz { Baz }
27 // fn foo() {
28 //     bar$0("", baz());
29 // }
30 //
31 // ```
32 // ->
33 // ```
34 // struct Baz;
35 // fn baz() -> Baz { Baz }
36 // fn foo() {
37 //     bar("", baz());
38 // }
39 //
40 // fn bar(arg: &str, baz: Baz) ${0:-> ()} {
41 //     todo!()
42 // }
43 //
44 // ```
45 pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
46     gen_fn(acc, ctx).or_else(|| gen_method(acc, ctx))
47 }
48
49 enum FuncExpr {
50     Func(ast::CallExpr),
51     Method(ast::MethodCallExpr),
52 }
53
54 impl FuncExpr {
55     fn arg_list(&self) -> Option<ast::ArgList> {
56         match self {
57             FuncExpr::Func(fn_call) => fn_call.arg_list(),
58             FuncExpr::Method(m_call) => m_call.arg_list(),
59         }
60     }
61
62     fn syntax(&self) -> &SyntaxNode {
63         match self {
64             FuncExpr::Func(fn_call) => fn_call.syntax(),
65             FuncExpr::Method(m_call) => m_call.syntax(),
66         }
67     }
68 }
69
70 fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
71     let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
72     let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
73     let path = path_expr.path()?;
74     let fn_name = fn_name(&path)?;
75     if ctx.sema.resolve_path(&path).is_some() {
76         // The function call already resolves, no need to add a function
77         return None;
78     }
79
80     let target_module;
81     let mut adt_name = None;
82
83     let (target, file, insert_offset) = match path.qualifier() {
84         Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
85             Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
86                 target_module = Some(module);
87                 get_fn_target(ctx, &target_module, call.clone())?
88             }
89             Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
90                 let current_module = current_module(call.syntax(), ctx)?;
91                 let module = adt.module(ctx.sema.db);
92                 target_module = if current_module == module { None } else { Some(module) };
93                 if current_module.krate() != module.krate() {
94                     return None;
95                 }
96                 let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
97                 let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
98                 adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
99                 (target, file, insert_offset)
100             }
101             _ => {
102                 return None;
103             }
104         },
105         _ => {
106             target_module = None;
107             get_fn_target(ctx, &target_module, call.clone())?
108         }
109     };
110     let function_builder = FunctionBuilder::from_call(ctx, &call, &path, target_module, target)?;
111     let text_range = call.syntax().text_range();
112     let label = format!("Generate {} function", function_builder.fn_name.clone());
113     add_func_to_accumulator(
114         acc,
115         ctx,
116         text_range,
117         function_builder,
118         insert_offset,
119         file,
120         adt_name,
121         label,
122     )
123 }
124
125 fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
126     let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
127     let fn_name = call.name_ref()?;
128     let adt = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references().as_adt()?;
129
130     let current_module = current_module(call.syntax(), ctx)?;
131     let target_module = adt.module(ctx.sema.db);
132
133     if current_module.krate() != target_module.krate() {
134         return None;
135     }
136     let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
137     let (target, insert_offset) = get_method_target(ctx, &target_module, &impl_)?;
138     let function_builder =
139         FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
140     let text_range = call.syntax().text_range();
141     let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
142     let label = format!("Generate {} method", function_builder.fn_name.clone());
143     add_func_to_accumulator(
144         acc,
145         ctx,
146         text_range,
147         function_builder,
148         insert_offset,
149         file,
150         adt_name,
151         label,
152     )
153 }
154
155 fn add_func_to_accumulator(
156     acc: &mut Assists,
157     ctx: &AssistContext,
158     text_range: TextRange,
159     function_builder: FunctionBuilder,
160     insert_offset: TextSize,
161     file: FileId,
162     adt_name: Option<hir::Name>,
163     label: String,
164 ) -> Option<()> {
165     acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
166         let function_template = function_builder.render();
167         let mut func = function_template.to_string(ctx.config.snippet_cap);
168         if let Some(name) = adt_name {
169             func = format!("\nimpl {} {{\n{}\n}}", name, func);
170         }
171         builder.edit_file(file);
172         match ctx.config.snippet_cap {
173             Some(cap) => builder.insert_snippet(cap, insert_offset, func),
174             None => builder.insert(insert_offset, func),
175         }
176     })
177 }
178
179 fn current_module(current_node: &SyntaxNode, ctx: &AssistContext) -> Option<Module> {
180     ctx.sema.scope(current_node).module()
181 }
182
183 fn get_adt_source(
184     ctx: &AssistContext,
185     adt: &hir::Adt,
186     fn_name: &str,
187 ) -> Option<(Option<ast::Impl>, FileId)> {
188     let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
189     let file = ctx.sema.parse(range.file_id);
190     let adt_source =
191         ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
192     find_struct_impl(ctx, &adt_source, fn_name).map(|impl_| (impl_, range.file_id))
193 }
194
195 struct FunctionTemplate {
196     leading_ws: String,
197     fn_def: ast::Fn,
198     ret_type: Option<ast::RetType>,
199     should_focus_return_type: bool,
200     trailing_ws: String,
201     tail_expr: ast::Expr,
202 }
203
204 impl FunctionTemplate {
205     fn to_string(&self, cap: Option<SnippetCap>) -> String {
206         let f = match cap {
207             Some(cap) => {
208                 let cursor = if self.should_focus_return_type {
209                     // Focus the return type if there is one
210                     if let Some(ref ret_type) = self.ret_type {
211                         ret_type.syntax()
212                     } else {
213                         self.tail_expr.syntax()
214                     }
215                 } else {
216                     self.tail_expr.syntax()
217                 };
218                 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(cursor))
219             }
220             None => self.fn_def.to_string(),
221         };
222
223         format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
224     }
225 }
226
227 struct FunctionBuilder {
228     target: GeneratedFunctionTarget,
229     fn_name: ast::Name,
230     type_params: Option<ast::GenericParamList>,
231     params: ast::ParamList,
232     ret_type: Option<ast::RetType>,
233     should_focus_return_type: bool,
234     needs_pub: bool,
235     is_async: bool,
236 }
237
238 impl FunctionBuilder {
239     /// Prepares a generated function that matches `call`.
240     /// The function is generated in `target_module` or next to `call`
241     fn from_call(
242         ctx: &AssistContext,
243         call: &ast::CallExpr,
244         path: &ast::Path,
245         target_module: Option<hir::Module>,
246         target: GeneratedFunctionTarget,
247     ) -> Option<Self> {
248         let needs_pub = target_module.is_some();
249         let target_module = target_module.or_else(|| current_module(target.syntax(), ctx))?;
250         let fn_name = fn_name(path)?;
251         let (type_params, params) = fn_args(ctx, target_module, FuncExpr::Func(call.clone()))?;
252
253         let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
254         let is_async = await_expr.is_some();
255
256         let (ret_type, should_focus_return_type) =
257             make_return_type(ctx, &ast::Expr::CallExpr(call.clone()), target_module);
258
259         Some(Self {
260             target,
261             fn_name,
262             type_params,
263             params,
264             ret_type,
265             should_focus_return_type,
266             needs_pub,
267             is_async,
268         })
269     }
270
271     fn from_method_call(
272         ctx: &AssistContext,
273         call: &ast::MethodCallExpr,
274         name: &ast::NameRef,
275         target_module: Module,
276         target: GeneratedFunctionTarget,
277     ) -> Option<Self> {
278         let needs_pub =
279             !module_is_descendant(&current_module(call.syntax(), ctx)?, &target_module, ctx);
280         let fn_name = make::name(&name.text());
281         let (type_params, params) = fn_args(ctx, target_module, FuncExpr::Method(call.clone()))?;
282
283         let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
284         let is_async = await_expr.is_some();
285
286         let (ret_type, should_focus_return_type) =
287             make_return_type(ctx, &ast::Expr::MethodCallExpr(call.clone()), target_module);
288
289         Some(Self {
290             target,
291             fn_name,
292             type_params,
293             params,
294             ret_type,
295             should_focus_return_type,
296             needs_pub,
297             is_async,
298         })
299     }
300
301     fn render(self) -> FunctionTemplate {
302         let placeholder_expr = make::ext::expr_todo();
303         let fn_body = make::block_expr(vec![], Some(placeholder_expr));
304         let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
305         let mut fn_def = make::fn_(
306             visibility,
307             self.fn_name,
308             self.type_params,
309             self.params,
310             fn_body,
311             self.ret_type,
312             self.is_async,
313         );
314         let leading_ws;
315         let trailing_ws;
316
317         match self.target {
318             GeneratedFunctionTarget::BehindItem(it) => {
319                 let indent = IndentLevel::from_node(&it);
320                 leading_ws = format!("\n\n{}", indent);
321                 fn_def = fn_def.indent(indent);
322                 trailing_ws = String::new();
323             }
324             GeneratedFunctionTarget::InEmptyItemList(it) => {
325                 let indent = IndentLevel::from_node(&it);
326                 leading_ws = format!("\n{}", indent + 1);
327                 fn_def = fn_def.indent(indent + 1);
328                 trailing_ws = format!("\n{}", indent);
329             }
330         };
331
332         FunctionTemplate {
333             leading_ws,
334             ret_type: fn_def.ret_type(),
335             // PANIC: we guarantee we always create a function body with a tail expr
336             tail_expr: fn_def.body().unwrap().tail_expr().unwrap(),
337             should_focus_return_type: self.should_focus_return_type,
338             fn_def,
339             trailing_ws,
340         }
341     }
342 }
343
344 /// Makes an optional return type along with whether the return type should be focused by the cursor.
345 /// If we cannot infer what the return type should be, we create unit as a placeholder.
346 ///
347 /// The rule for whether we focus a return type or not (and thus focus the function body),
348 /// is rather simple:
349 /// * If we could *not* infer what the return type should be, focus it (so the user can fill-in
350 /// the correct return type).
351 /// * If we could infer the return type, don't focus it (and thus focus the function body) so the
352 /// user can change the `todo!` function body.
353 fn make_return_type(
354     ctx: &AssistContext,
355     call: &ast::Expr,
356     target_module: Module,
357 ) -> (Option<ast::RetType>, bool) {
358     let (ret_ty, should_focus_return_type) = {
359         match ctx.sema.type_of_expr(call).map(TypeInfo::original) {
360             Some(ty) if ty.is_unknown() => (Some(make::ty_unit()), true),
361             None => (Some(make::ty_unit()), true),
362             Some(ty) if ty.is_unit() => (None, false),
363             Some(ty) => {
364                 let rendered = ty.display_source_code(ctx.db(), target_module.into());
365                 match rendered {
366                     Ok(rendered) => (Some(make::ty(&rendered)), false),
367                     Err(_) => (Some(make::ty_unit()), true),
368                 }
369             }
370         }
371     };
372     let ret_type = ret_ty.map(|rt| make::ret_type(rt));
373     (ret_type, should_focus_return_type)
374 }
375
376 fn get_fn_target(
377     ctx: &AssistContext,
378     target_module: &Option<Module>,
379     call: CallExpr,
380 ) -> Option<(GeneratedFunctionTarget, FileId, TextSize)> {
381     let mut file = ctx.frange.file_id;
382     let target = match target_module {
383         Some(target_module) => {
384             let module_source = target_module.definition_source(ctx.db());
385             let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
386             file = in_file;
387             target
388         }
389         None => next_space_for_fn_after_call_site(FuncExpr::Func(call.clone()))?,
390     };
391     Some((target.clone(), file, get_insert_offset(&target)))
392 }
393
394 fn get_method_target(
395     ctx: &AssistContext,
396     target_module: &Module,
397     impl_: &Option<ast::Impl>,
398 ) -> Option<(GeneratedFunctionTarget, TextSize)> {
399     let target = match impl_ {
400         Some(impl_) => next_space_for_fn_in_impl(&impl_)?,
401         None => {
402             next_space_for_fn_in_module(ctx.sema.db, &target_module.definition_source(ctx.sema.db))?
403                 .1
404         }
405     };
406     Some((target.clone(), get_insert_offset(&target)))
407 }
408
409 fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize {
410     match &target {
411         GeneratedFunctionTarget::BehindItem(it) => it.text_range().end(),
412         GeneratedFunctionTarget::InEmptyItemList(it) => it.text_range().start() + TextSize::of('{'),
413     }
414 }
415
416 #[derive(Clone)]
417 enum GeneratedFunctionTarget {
418     BehindItem(SyntaxNode),
419     InEmptyItemList(SyntaxNode),
420 }
421
422 impl GeneratedFunctionTarget {
423     fn syntax(&self) -> &SyntaxNode {
424         match self {
425             GeneratedFunctionTarget::BehindItem(it) => it,
426             GeneratedFunctionTarget::InEmptyItemList(it) => it,
427         }
428     }
429 }
430
431 fn fn_name(call: &ast::Path) -> Option<ast::Name> {
432     let name = call.segment()?.syntax().to_string();
433     Some(make::name(&name))
434 }
435
436 /// Computes the type variables and arguments required for the generated function
437 fn fn_args(
438     ctx: &AssistContext,
439     target_module: hir::Module,
440     call: FuncExpr,
441 ) -> Option<(Option<ast::GenericParamList>, ast::ParamList)> {
442     let mut arg_names = Vec::new();
443     let mut arg_types = Vec::new();
444     for arg in call.arg_list()?.args() {
445         arg_names.push(match fn_arg_name(&arg) {
446             Some(name) => name,
447             None => String::from("arg"),
448         });
449         arg_types.push(match fn_arg_type(ctx, target_module, &arg) {
450             Some(ty) => {
451                 if ty.len() > 0 && ty.starts_with('&') {
452                     if let Some((new_ty, _)) = useless_type_special_case("", &ty[1..].to_owned()) {
453                         new_ty
454                     } else {
455                         ty
456                     }
457                 } else {
458                     ty
459                 }
460             }
461             None => String::from("()"),
462         });
463     }
464     deduplicate_arg_names(&mut arg_names);
465     let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| {
466         make::param(make::ext::simple_ident_pat(make::name(&name)).into(), make::ty(&ty))
467     });
468
469     Some((
470         None,
471         make::param_list(
472             match call {
473                 FuncExpr::Func(_) => None,
474                 FuncExpr::Method(_) => Some(make::self_param()),
475             },
476             params,
477         ),
478     ))
479 }
480
481 /// Makes duplicate argument names unique by appending incrementing numbers.
482 ///
483 /// ```
484 /// let mut names: Vec<String> =
485 ///     vec!["foo".into(), "foo".into(), "bar".into(), "baz".into(), "bar".into()];
486 /// deduplicate_arg_names(&mut names);
487 /// let expected: Vec<String> =
488 ///     vec!["foo_1".into(), "foo_2".into(), "bar_1".into(), "baz".into(), "bar_2".into()];
489 /// assert_eq!(names, expected);
490 /// ```
491 fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
492     let arg_name_counts = arg_names.iter().fold(FxHashMap::default(), |mut m, name| {
493         *m.entry(name).or_insert(0) += 1;
494         m
495     });
496     let duplicate_arg_names: FxHashSet<String> = arg_name_counts
497         .into_iter()
498         .filter(|(_, count)| *count >= 2)
499         .map(|(name, _)| name.clone())
500         .collect();
501
502     let mut counter_per_name = FxHashMap::default();
503     for arg_name in arg_names.iter_mut() {
504         if duplicate_arg_names.contains(arg_name) {
505             let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
506             arg_name.push('_');
507             arg_name.push_str(&counter.to_string());
508             *counter += 1;
509         }
510     }
511 }
512
513 fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
514     match fn_arg {
515         ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
516         _ => {
517             let s = fn_arg
518                 .syntax()
519                 .descendants()
520                 .filter(|d| ast::NameRef::can_cast(d.kind()))
521                 .last()?
522                 .to_string();
523             Some(to_lower_snake_case(&s))
524         }
525     }
526 }
527
528 fn fn_arg_type(
529     ctx: &AssistContext,
530     target_module: hir::Module,
531     fn_arg: &ast::Expr,
532 ) -> Option<String> {
533     let ty = ctx.sema.type_of_expr(fn_arg)?.adjusted();
534     if ty.is_unknown() {
535         return None;
536     }
537
538     if let Ok(rendered) = ty.display_source_code(ctx.db(), target_module.into()) {
539         Some(rendered)
540     } else {
541         None
542     }
543 }
544
545 /// Returns the position inside the current mod or file
546 /// directly after the current block
547 /// We want to write the generated function directly after
548 /// fns, impls or macro calls, but inside mods
549 fn next_space_for_fn_after_call_site(expr: FuncExpr) -> Option<GeneratedFunctionTarget> {
550     let mut ancestors = expr.syntax().ancestors().peekable();
551     let mut last_ancestor: Option<SyntaxNode> = None;
552     while let Some(next_ancestor) = ancestors.next() {
553         match next_ancestor.kind() {
554             SyntaxKind::SOURCE_FILE => {
555                 break;
556             }
557             SyntaxKind::ITEM_LIST => {
558                 if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) {
559                     break;
560                 }
561             }
562             _ => {}
563         }
564         last_ancestor = Some(next_ancestor);
565     }
566     last_ancestor.map(GeneratedFunctionTarget::BehindItem)
567 }
568
569 fn next_space_for_fn_in_module(
570     db: &dyn hir::db::AstDatabase,
571     module_source: &hir::InFile<hir::ModuleSource>,
572 ) -> Option<(FileId, GeneratedFunctionTarget)> {
573     let file = module_source.file_id.original_file(db);
574     let assist_item = match &module_source.value {
575         hir::ModuleSource::SourceFile(it) => {
576             if let Some(last_item) = it.items().last() {
577                 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
578             } else {
579                 GeneratedFunctionTarget::BehindItem(it.syntax().clone())
580             }
581         }
582         hir::ModuleSource::Module(it) => {
583             if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) {
584                 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
585             } else {
586                 GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone())
587             }
588         }
589         hir::ModuleSource::BlockExpr(it) => {
590             if let Some(last_item) =
591                 it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
592             {
593                 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
594             } else {
595                 GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
596             }
597         }
598     };
599     Some((file, assist_item))
600 }
601
602 fn next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarget> {
603     if let Some(last_item) = impl_.assoc_item_list().and_then(|it| it.assoc_items().last()) {
604         Some(GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()))
605     } else {
606         Some(GeneratedFunctionTarget::InEmptyItemList(impl_.assoc_item_list()?.syntax().clone()))
607     }
608 }
609
610 fn module_is_descendant(module: &hir::Module, ans: &hir::Module, ctx: &AssistContext) -> bool {
611     if module == ans {
612         return true;
613     }
614     for c in ans.children(ctx.sema.db) {
615         if module_is_descendant(module, &c, ctx) {
616             return true;
617         }
618     }
619     false
620 }
621
622 #[cfg(test)]
623 mod tests {
624     use crate::tests::{check_assist, check_assist_not_applicable};
625
626     use super::*;
627
628     #[test]
629     fn add_function_with_no_args() {
630         check_assist(
631             generate_function,
632             r"
633 fn foo() {
634     bar$0();
635 }
636 ",
637             r"
638 fn foo() {
639     bar();
640 }
641
642 fn bar() ${0:-> ()} {
643     todo!()
644 }
645 ",
646         )
647     }
648
649     #[test]
650     fn add_function_from_method() {
651         // This ensures that the function is correctly generated
652         // in the next outer mod or file
653         check_assist(
654             generate_function,
655             r"
656 impl Foo {
657     fn foo() {
658         bar$0();
659     }
660 }
661 ",
662             r"
663 impl Foo {
664     fn foo() {
665         bar();
666     }
667 }
668
669 fn bar() ${0:-> ()} {
670     todo!()
671 }
672 ",
673         )
674     }
675
676     #[test]
677     fn add_function_directly_after_current_block() {
678         // The new fn should not be created at the end of the file or module
679         check_assist(
680             generate_function,
681             r"
682 fn foo1() {
683     bar$0();
684 }
685
686 fn foo2() {}
687 ",
688             r"
689 fn foo1() {
690     bar();
691 }
692
693 fn bar() ${0:-> ()} {
694     todo!()
695 }
696
697 fn foo2() {}
698 ",
699         )
700     }
701
702     #[test]
703     fn add_function_with_no_args_in_same_module() {
704         check_assist(
705             generate_function,
706             r"
707 mod baz {
708     fn foo() {
709         bar$0();
710     }
711 }
712 ",
713             r"
714 mod baz {
715     fn foo() {
716         bar();
717     }
718
719     fn bar() ${0:-> ()} {
720         todo!()
721     }
722 }
723 ",
724         )
725     }
726
727     #[test]
728     fn add_function_with_upper_camel_case_arg() {
729         check_assist(
730             generate_function,
731             r"
732 struct BazBaz;
733 fn foo() {
734     bar$0(BazBaz);
735 }
736 ",
737             r"
738 struct BazBaz;
739 fn foo() {
740     bar(BazBaz);
741 }
742
743 fn bar(baz_baz: BazBaz) ${0:-> ()} {
744     todo!()
745 }
746 ",
747         );
748     }
749
750     #[test]
751     fn add_function_with_upper_camel_case_arg_as_cast() {
752         check_assist(
753             generate_function,
754             r"
755 struct BazBaz;
756 fn foo() {
757     bar$0(&BazBaz as *const BazBaz);
758 }
759 ",
760             r"
761 struct BazBaz;
762 fn foo() {
763     bar(&BazBaz as *const BazBaz);
764 }
765
766 fn bar(baz_baz: *const BazBaz) ${0:-> ()} {
767     todo!()
768 }
769 ",
770         );
771     }
772
773     #[test]
774     fn add_function_with_function_call_arg() {
775         check_assist(
776             generate_function,
777             r"
778 struct Baz;
779 fn baz() -> Baz { todo!() }
780 fn foo() {
781     bar$0(baz());
782 }
783 ",
784             r"
785 struct Baz;
786 fn baz() -> Baz { todo!() }
787 fn foo() {
788     bar(baz());
789 }
790
791 fn bar(baz: Baz) ${0:-> ()} {
792     todo!()
793 }
794 ",
795         );
796     }
797
798     #[test]
799     fn add_function_with_method_call_arg() {
800         check_assist(
801             generate_function,
802             r"
803 struct Baz;
804 impl Baz {
805     fn foo(&self) -> Baz {
806         ba$0r(self.baz())
807     }
808     fn baz(&self) -> Baz {
809         Baz
810     }
811 }
812 ",
813             r"
814 struct Baz;
815 impl Baz {
816     fn foo(&self) -> Baz {
817         bar(self.baz())
818     }
819     fn baz(&self) -> Baz {
820         Baz
821     }
822 }
823
824 fn bar(baz: Baz) -> Baz {
825     ${0:todo!()}
826 }
827 ",
828         )
829     }
830
831     #[test]
832     fn add_function_with_string_literal_arg() {
833         check_assist(
834             generate_function,
835             r#"
836 fn foo() {
837     $0bar("bar")
838 }
839 "#,
840             r#"
841 fn foo() {
842     bar("bar")
843 }
844
845 fn bar(arg: &str) {
846     ${0:todo!()}
847 }
848 "#,
849         )
850     }
851
852     #[test]
853     fn add_function_with_char_literal_arg() {
854         check_assist(
855             generate_function,
856             r#"
857 fn foo() {
858     $0bar('x')
859 }
860 "#,
861             r#"
862 fn foo() {
863     bar('x')
864 }
865
866 fn bar(arg: char) {
867     ${0:todo!()}
868 }
869 "#,
870         )
871     }
872
873     #[test]
874     fn add_function_with_int_literal_arg() {
875         check_assist(
876             generate_function,
877             r"
878 fn foo() {
879     $0bar(42)
880 }
881 ",
882             r"
883 fn foo() {
884     bar(42)
885 }
886
887 fn bar(arg: i32) {
888     ${0:todo!()}
889 }
890 ",
891         )
892     }
893
894     #[test]
895     fn add_function_with_cast_int_literal_arg() {
896         check_assist(
897             generate_function,
898             r"
899 fn foo() {
900     $0bar(42 as u8)
901 }
902 ",
903             r"
904 fn foo() {
905     bar(42 as u8)
906 }
907
908 fn bar(arg: u8) {
909     ${0:todo!()}
910 }
911 ",
912         )
913     }
914
915     #[test]
916     fn name_of_cast_variable_is_used() {
917         // Ensures that the name of the cast type isn't used
918         // in the generated function signature.
919         check_assist(
920             generate_function,
921             r"
922 fn foo() {
923     let x = 42;
924     bar$0(x as u8)
925 }
926 ",
927             r"
928 fn foo() {
929     let x = 42;
930     bar(x as u8)
931 }
932
933 fn bar(x: u8) {
934     ${0:todo!()}
935 }
936 ",
937         )
938     }
939
940     #[test]
941     fn add_function_with_variable_arg() {
942         check_assist(
943             generate_function,
944             r"
945 fn foo() {
946     let worble = ();
947     $0bar(worble)
948 }
949 ",
950             r"
951 fn foo() {
952     let worble = ();
953     bar(worble)
954 }
955
956 fn bar(worble: ()) {
957     ${0:todo!()}
958 }
959 ",
960         )
961     }
962
963     #[test]
964     fn add_function_with_impl_trait_arg() {
965         check_assist(
966             generate_function,
967             r#"
968 //- minicore: sized
969 trait Foo {}
970 fn foo() -> impl Foo {
971     todo!()
972 }
973 fn baz() {
974     $0bar(foo())
975 }
976 "#,
977             r#"
978 trait Foo {}
979 fn foo() -> impl Foo {
980     todo!()
981 }
982 fn baz() {
983     bar(foo())
984 }
985
986 fn bar(foo: impl Foo) {
987     ${0:todo!()}
988 }
989 "#,
990         )
991     }
992
993     #[test]
994     fn borrowed_arg() {
995         check_assist(
996             generate_function,
997             r"
998 struct Baz;
999 fn baz() -> Baz { todo!() }
1000
1001 fn foo() {
1002     bar$0(&baz())
1003 }
1004 ",
1005             r"
1006 struct Baz;
1007 fn baz() -> Baz { todo!() }
1008
1009 fn foo() {
1010     bar(&baz())
1011 }
1012
1013 fn bar(baz: &Baz) {
1014     ${0:todo!()}
1015 }
1016 ",
1017         )
1018     }
1019
1020     #[test]
1021     fn add_function_with_qualified_path_arg() {
1022         check_assist(
1023             generate_function,
1024             r"
1025 mod Baz {
1026     pub struct Bof;
1027     pub fn baz() -> Bof { Bof }
1028 }
1029 fn foo() {
1030     $0bar(Baz::baz())
1031 }
1032 ",
1033             r"
1034 mod Baz {
1035     pub struct Bof;
1036     pub fn baz() -> Bof { Bof }
1037 }
1038 fn foo() {
1039     bar(Baz::baz())
1040 }
1041
1042 fn bar(baz: Baz::Bof) {
1043     ${0:todo!()}
1044 }
1045 ",
1046         )
1047     }
1048
1049     #[test]
1050     fn add_function_with_generic_arg() {
1051         // FIXME: This is wrong, generated `bar` should include generic parameter.
1052         check_assist(
1053             generate_function,
1054             r"
1055 fn foo<T>(t: T) {
1056     $0bar(t)
1057 }
1058 ",
1059             r"
1060 fn foo<T>(t: T) {
1061     bar(t)
1062 }
1063
1064 fn bar(t: T) {
1065     ${0:todo!()}
1066 }
1067 ",
1068         )
1069     }
1070
1071     #[test]
1072     fn add_function_with_fn_arg() {
1073         // FIXME: The argument in `bar` is wrong.
1074         check_assist(
1075             generate_function,
1076             r"
1077 struct Baz;
1078 impl Baz {
1079     fn new() -> Self { Baz }
1080 }
1081 fn foo() {
1082     $0bar(Baz::new);
1083 }
1084 ",
1085             r"
1086 struct Baz;
1087 impl Baz {
1088     fn new() -> Self { Baz }
1089 }
1090 fn foo() {
1091     bar(Baz::new);
1092 }
1093
1094 fn bar(new: fn) ${0:-> ()} {
1095     todo!()
1096 }
1097 ",
1098         )
1099     }
1100
1101     #[test]
1102     fn add_function_with_closure_arg() {
1103         // FIXME: The argument in `bar` is wrong.
1104         check_assist(
1105             generate_function,
1106             r"
1107 fn foo() {
1108     let closure = |x: i64| x - 1;
1109     $0bar(closure)
1110 }
1111 ",
1112             r"
1113 fn foo() {
1114     let closure = |x: i64| x - 1;
1115     bar(closure)
1116 }
1117
1118 fn bar(closure: ()) {
1119     ${0:todo!()}
1120 }
1121 ",
1122         )
1123     }
1124
1125     #[test]
1126     fn unresolveable_types_default_to_unit() {
1127         check_assist(
1128             generate_function,
1129             r"
1130 fn foo() {
1131     $0bar(baz)
1132 }
1133 ",
1134             r"
1135 fn foo() {
1136     bar(baz)
1137 }
1138
1139 fn bar(baz: ()) {
1140     ${0:todo!()}
1141 }
1142 ",
1143         )
1144     }
1145
1146     #[test]
1147     fn arg_names_dont_overlap() {
1148         check_assist(
1149             generate_function,
1150             r"
1151 struct Baz;
1152 fn baz() -> Baz { Baz }
1153 fn foo() {
1154     $0bar(baz(), baz())
1155 }
1156 ",
1157             r"
1158 struct Baz;
1159 fn baz() -> Baz { Baz }
1160 fn foo() {
1161     bar(baz(), baz())
1162 }
1163
1164 fn bar(baz_1: Baz, baz_2: Baz) {
1165     ${0:todo!()}
1166 }
1167 ",
1168         )
1169     }
1170
1171     #[test]
1172     fn arg_name_counters_start_at_1_per_name() {
1173         check_assist(
1174             generate_function,
1175             r#"
1176 struct Baz;
1177 fn baz() -> Baz { Baz }
1178 fn foo() {
1179     $0bar(baz(), baz(), "foo", "bar")
1180 }
1181 "#,
1182             r#"
1183 struct Baz;
1184 fn baz() -> Baz { Baz }
1185 fn foo() {
1186     bar(baz(), baz(), "foo", "bar")
1187 }
1188
1189 fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
1190     ${0:todo!()}
1191 }
1192 "#,
1193         )
1194     }
1195
1196     #[test]
1197     fn add_function_in_module() {
1198         check_assist(
1199             generate_function,
1200             r"
1201 mod bar {}
1202
1203 fn foo() {
1204     bar::my_fn$0()
1205 }
1206 ",
1207             r"
1208 mod bar {
1209     pub(crate) fn my_fn() {
1210         ${0:todo!()}
1211     }
1212 }
1213
1214 fn foo() {
1215     bar::my_fn()
1216 }
1217 ",
1218         )
1219     }
1220
1221     #[test]
1222     fn qualified_path_uses_correct_scope() {
1223         check_assist(
1224             generate_function,
1225             r#"
1226 mod foo {
1227     pub struct Foo;
1228 }
1229 fn bar() {
1230     use foo::Foo;
1231     let foo = Foo;
1232     baz$0(foo)
1233 }
1234 "#,
1235             r#"
1236 mod foo {
1237     pub struct Foo;
1238 }
1239 fn bar() {
1240     use foo::Foo;
1241     let foo = Foo;
1242     baz(foo)
1243 }
1244
1245 fn baz(foo: foo::Foo) {
1246     ${0:todo!()}
1247 }
1248 "#,
1249         )
1250     }
1251
1252     #[test]
1253     fn add_function_in_module_containing_other_items() {
1254         check_assist(
1255             generate_function,
1256             r"
1257 mod bar {
1258     fn something_else() {}
1259 }
1260
1261 fn foo() {
1262     bar::my_fn$0()
1263 }
1264 ",
1265             r"
1266 mod bar {
1267     fn something_else() {}
1268
1269     pub(crate) fn my_fn() {
1270         ${0:todo!()}
1271     }
1272 }
1273
1274 fn foo() {
1275     bar::my_fn()
1276 }
1277 ",
1278         )
1279     }
1280
1281     #[test]
1282     fn add_function_in_nested_module() {
1283         check_assist(
1284             generate_function,
1285             r"
1286 mod bar {
1287     mod baz {}
1288 }
1289
1290 fn foo() {
1291     bar::baz::my_fn$0()
1292 }
1293 ",
1294             r"
1295 mod bar {
1296     mod baz {
1297         pub(crate) fn my_fn() {
1298             ${0:todo!()}
1299         }
1300     }
1301 }
1302
1303 fn foo() {
1304     bar::baz::my_fn()
1305 }
1306 ",
1307         )
1308     }
1309
1310     #[test]
1311     fn add_function_in_another_file() {
1312         check_assist(
1313             generate_function,
1314             r"
1315 //- /main.rs
1316 mod foo;
1317
1318 fn main() {
1319     foo::bar$0()
1320 }
1321 //- /foo.rs
1322 ",
1323             r"
1324
1325
1326 pub(crate) fn bar() {
1327     ${0:todo!()}
1328 }",
1329         )
1330     }
1331
1332     #[test]
1333     fn add_function_with_return_type() {
1334         check_assist(
1335             generate_function,
1336             r"
1337 fn main() {
1338     let x: u32 = foo$0();
1339 }
1340 ",
1341             r"
1342 fn main() {
1343     let x: u32 = foo();
1344 }
1345
1346 fn foo() -> u32 {
1347     ${0:todo!()}
1348 }
1349 ",
1350         )
1351     }
1352
1353     #[test]
1354     fn add_function_not_applicable_if_function_already_exists() {
1355         check_assist_not_applicable(
1356             generate_function,
1357             r"
1358 fn foo() {
1359     bar$0();
1360 }
1361
1362 fn bar() {}
1363 ",
1364         )
1365     }
1366
1367     #[test]
1368     fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
1369         check_assist_not_applicable(
1370             // bar is resolved, but baz isn't.
1371             // The assist is only active if the cursor is on an unresolved path,
1372             // but the assist should only be offered if the path is a function call.
1373             generate_function,
1374             r#"
1375 fn foo() {
1376     bar(b$0az);
1377 }
1378
1379 fn bar(baz: ()) {}
1380 "#,
1381         )
1382     }
1383
1384     #[test]
1385     fn create_method_with_no_args() {
1386         check_assist(
1387             generate_function,
1388             r#"
1389 struct Foo;
1390 impl Foo {
1391     fn foo(&self) {
1392         self.bar()$0;
1393     }
1394 }
1395 "#,
1396             r#"
1397 struct Foo;
1398 impl Foo {
1399     fn foo(&self) {
1400         self.bar();
1401     }
1402
1403     fn bar(&self) ${0:-> ()} {
1404         todo!()
1405     }
1406 }
1407 "#,
1408         )
1409     }
1410
1411     #[test]
1412     fn create_function_with_async() {
1413         check_assist(
1414             generate_function,
1415             r"
1416 fn foo() {
1417     $0bar(42).await();
1418 }
1419 ",
1420             r"
1421 fn foo() {
1422     bar(42).await();
1423 }
1424
1425 async fn bar(arg: i32) ${0:-> ()} {
1426     todo!()
1427 }
1428 ",
1429         )
1430     }
1431
1432     #[test]
1433     fn create_method() {
1434         check_assist(
1435             generate_function,
1436             r"
1437 struct S;
1438 fn foo() {S.bar$0();}
1439 ",
1440             r"
1441 struct S;
1442 fn foo() {S.bar();}
1443 impl S {
1444
1445
1446 fn bar(&self) ${0:-> ()} {
1447     todo!()
1448 }
1449 }
1450 ",
1451         )
1452     }
1453
1454     #[test]
1455     fn create_method_within_an_impl() {
1456         check_assist(
1457             generate_function,
1458             r"
1459 struct S;
1460 fn foo() {S.bar$0();}
1461 impl S {}
1462
1463 ",
1464             r"
1465 struct S;
1466 fn foo() {S.bar();}
1467 impl S {
1468     fn bar(&self) ${0:-> ()} {
1469         todo!()
1470     }
1471 }
1472
1473 ",
1474         )
1475     }
1476
1477     #[test]
1478     fn create_method_from_different_module() {
1479         check_assist(
1480             generate_function,
1481             r"
1482 mod s {
1483     pub struct S;
1484 }
1485 fn foo() {s::S.bar$0();}
1486 ",
1487             r"
1488 mod s {
1489     pub struct S;
1490 impl S {
1491
1492
1493     pub(crate) fn bar(&self) ${0:-> ()} {
1494         todo!()
1495     }
1496 }
1497 }
1498 fn foo() {s::S.bar();}
1499 ",
1500         )
1501     }
1502
1503     #[test]
1504     fn create_method_from_descendant_module() {
1505         check_assist(
1506             generate_function,
1507             r"
1508 struct S;
1509 mod s {
1510     fn foo() {
1511         super::S.bar$0();
1512     }
1513 }
1514
1515 ",
1516             r"
1517 struct S;
1518 mod s {
1519     fn foo() {
1520         super::S.bar();
1521     }
1522 }
1523 impl S {
1524
1525
1526 fn bar(&self) ${0:-> ()} {
1527     todo!()
1528 }
1529 }
1530
1531 ",
1532         )
1533     }
1534
1535     #[test]
1536     fn create_method_with_cursor_anywhere_on_call_expresion() {
1537         check_assist(
1538             generate_function,
1539             r"
1540 struct S;
1541 fn foo() {$0S.bar();}
1542 ",
1543             r"
1544 struct S;
1545 fn foo() {S.bar();}
1546 impl S {
1547
1548
1549 fn bar(&self) ${0:-> ()} {
1550     todo!()
1551 }
1552 }
1553 ",
1554         )
1555     }
1556
1557     #[test]
1558     fn create_static_method() {
1559         check_assist(
1560             generate_function,
1561             r"
1562 struct S;
1563 fn foo() {S::bar$0();}
1564 ",
1565             r"
1566 struct S;
1567 fn foo() {S::bar();}
1568 impl S {
1569
1570
1571 fn bar() ${0:-> ()} {
1572     todo!()
1573 }
1574 }
1575 ",
1576         )
1577     }
1578
1579     #[test]
1580     fn create_static_method_within_an_impl() {
1581         check_assist(
1582             generate_function,
1583             r"
1584 struct S;
1585 fn foo() {S::bar$0();}
1586 impl S {}
1587
1588 ",
1589             r"
1590 struct S;
1591 fn foo() {S::bar();}
1592 impl S {
1593     fn bar() ${0:-> ()} {
1594         todo!()
1595     }
1596 }
1597
1598 ",
1599         )
1600     }
1601
1602     #[test]
1603     fn create_static_method_from_different_module() {
1604         check_assist(
1605             generate_function,
1606             r"
1607 mod s {
1608     pub struct S;
1609 }
1610 fn foo() {s::S::bar$0();}
1611 ",
1612             r"
1613 mod s {
1614     pub struct S;
1615 impl S {
1616
1617
1618     pub(crate) fn bar() ${0:-> ()} {
1619         todo!()
1620     }
1621 }
1622 }
1623 fn foo() {s::S::bar();}
1624 ",
1625         )
1626     }
1627
1628     #[test]
1629     fn create_static_method_with_cursor_anywhere_on_call_expresion() {
1630         check_assist(
1631             generate_function,
1632             r"
1633 struct S;
1634 fn foo() {$0S::bar();}
1635 ",
1636             r"
1637 struct S;
1638 fn foo() {S::bar();}
1639 impl S {
1640
1641
1642 fn bar() ${0:-> ()} {
1643     todo!()
1644 }
1645 }
1646 ",
1647         )
1648     }
1649 }