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