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