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