]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/inline_call.rs
Merge #11481
[rust.git] / crates / ide_assists / src / handlers / inline_call.rs
1 use ast::make;
2 use either::Either;
3 use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
4 use ide_db::{
5     base_db::{FileId, FileRange},
6     defs::Definition,
7     helpers::{insert_use::remove_path_if_in_use_stmt, node_ext::expr_as_name_ref},
8     path_transform::PathTransform,
9     search::{FileReference, SearchScope},
10     RootDatabase,
11 };
12 use itertools::{izip, Itertools};
13 use syntax::{
14     ast::{self, edit_in_place::Indent, HasArgList, PathExpr},
15     ted, AstNode,
16 };
17
18 use crate::{
19     assist_context::{AssistContext, Assists},
20     AssistId, AssistKind,
21 };
22
23 // Assist: inline_into_callers
24 //
25 // Inline a function or method body into all of its callers where possible, creating a `let` statement per parameter
26 // unless the parameter can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
27 // or if the parameter is only accessed inside the function body once.
28 // If all calls can be inlined the function will be removed.
29 //
30 // ```
31 // fn print(_: &str) {}
32 // fn foo$0(word: &str) {
33 //     if !word.is_empty() {
34 //         print(word);
35 //     }
36 // }
37 // fn bar() {
38 //     foo("안녕하세요");
39 //     foo("여러분");
40 // }
41 // ```
42 // ->
43 // ```
44 // fn print(_: &str) {}
45 //
46 // fn bar() {
47 //     {
48 //         let word = "안녕하세요";
49 //         if !word.is_empty() {
50 //             print(word);
51 //         }
52 //     };
53 //     {
54 //         let word = "여러분";
55 //         if !word.is_empty() {
56 //             print(word);
57 //         }
58 //     };
59 // }
60 // ```
61 pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
62     let def_file = ctx.file_id();
63     let name = ctx.find_node_at_offset::<ast::Name>()?;
64     let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
65     let func_body = ast_func.body()?;
66     let param_list = ast_func.param_list()?;
67
68     let function = ctx.sema.to_def(&ast_func)?;
69
70     let params = get_fn_params(ctx.sema.db, function, &param_list)?;
71
72     let usages = Definition::Function(function).usages(&ctx.sema);
73     if !usages.at_least_one() {
74         return None;
75     }
76
77     let is_recursive_fn = usages
78         .clone()
79         .in_scope(SearchScope::file_range(FileRange {
80             file_id: def_file,
81             range: func_body.syntax().text_range(),
82         }))
83         .at_least_one();
84     if is_recursive_fn {
85         cov_mark::hit!(inline_into_callers_recursive);
86         return None;
87     }
88
89     acc.add(
90         AssistId("inline_into_callers", AssistKind::RefactorInline),
91         "Inline into all callers",
92         name.syntax().text_range(),
93         |builder| {
94             let mut usages = usages.all();
95             let current_file_usage = usages.references.remove(&def_file);
96
97             let mut remove_def = true;
98             let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
99                 builder.edit_file(file_id);
100                 let count = refs.len();
101                 // The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️
102                 let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs
103                     .into_iter()
104                     .filter_map(|file_ref| match file_ref.name {
105                         ast::NameLike::NameRef(name_ref) => Some(name_ref),
106                         _ => None,
107                     })
108                     .partition_map(|name_ref| {
109                         match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
110                             Some(use_tree) => Either::Right(builder.make_mut(use_tree)),
111                             None => Either::Left(name_ref),
112                         }
113                     });
114                 let call_infos: Vec<_> = name_refs
115                     .into_iter()
116                     .filter_map(CallInfo::from_name_ref)
117                     .map(|call_info| {
118                         let mut_node = builder.make_syntax_mut(call_info.node.syntax().clone());
119                         (call_info, mut_node)
120                     })
121                     .collect();
122                 let replaced = call_infos
123                     .into_iter()
124                     .map(|(call_info, mut_node)| {
125                         let replacement =
126                             inline(&ctx.sema, def_file, function, &func_body, &params, &call_info);
127                         ted::replace(mut_node, replacement.syntax());
128                     })
129                     .count();
130                 if replaced + name_refs_use.len() == count {
131                     // we replaced all usages in this file, so we can remove the imports
132                     name_refs_use.into_iter().for_each(|use_tree| {
133                         if let Some(path) = use_tree.path() {
134                             remove_path_if_in_use_stmt(&path);
135                         }
136                     })
137                 } else {
138                     remove_def = false;
139                 }
140             };
141             for (file_id, refs) in usages.into_iter() {
142                 inline_refs_for_file(file_id, refs);
143             }
144             match current_file_usage {
145                 Some(refs) => inline_refs_for_file(def_file, refs),
146                 None => builder.edit_file(def_file),
147             }
148             if remove_def {
149                 builder.delete(ast_func.syntax().text_range());
150             }
151         },
152     )
153 }
154
155 // Assist: inline_call
156 //
157 // Inlines a function or method body creating a `let` statement per parameter unless the parameter
158 // can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
159 // or if the parameter is only accessed inside the function body once.
160 //
161 // ```
162 // # //- minicore: option
163 // fn foo(name: Option<&str>) {
164 //     let name = name.unwrap$0();
165 // }
166 // ```
167 // ->
168 // ```
169 // fn foo(name: Option<&str>) {
170 //     let name = match name {
171 //             Some(val) => val,
172 //             None => panic!("called `Option::unwrap()` on a `None` value"),
173 //         };
174 // }
175 // ```
176 pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
177     let name_ref: ast::NameRef = ctx.find_node_at_offset()?;
178     let call_info = CallInfo::from_name_ref(name_ref.clone())?;
179     let (function, label) = match &call_info.node {
180         ast::CallableExpr::Call(call) => {
181             let path = match call.expr()? {
182                 ast::Expr::PathExpr(path) => path.path(),
183                 _ => None,
184             }?;
185             let function = match ctx.sema.resolve_path(&path)? {
186                 PathResolution::Def(hir::ModuleDef::Function(f)) => f,
187                 PathResolution::AssocItem(hir::AssocItem::Function(f)) => f,
188                 _ => return None,
189             };
190             (function, format!("Inline `{}`", path))
191         }
192         ast::CallableExpr::MethodCall(call) => {
193             (ctx.sema.resolve_method_call(call)?, format!("Inline `{}`", name_ref))
194         }
195     };
196
197     let fn_source = ctx.sema.source(function)?;
198     let fn_body = fn_source.value.body()?;
199     let param_list = fn_source.value.param_list()?;
200
201     let FileRange { file_id, range } = fn_source.syntax().original_file_range(ctx.sema.db);
202     if file_id == ctx.file_id() && range.contains(ctx.offset()) {
203         cov_mark::hit!(inline_call_recursive);
204         return None;
205     }
206     let params = get_fn_params(ctx.sema.db, function, &param_list)?;
207
208     if call_info.arguments.len() != params.len() {
209         // Can't inline the function because they've passed the wrong number of
210         // arguments to this function
211         cov_mark::hit!(inline_call_incorrect_number_of_arguments);
212         return None;
213     }
214
215     let syntax = call_info.node.syntax().clone();
216     acc.add(
217         AssistId("inline_call", AssistKind::RefactorInline),
218         label,
219         syntax.text_range(),
220         |builder| {
221             let replacement = inline(&ctx.sema, file_id, function, &fn_body, &params, &call_info);
222
223             builder.replace_ast(
224                 match call_info.node {
225                     ast::CallableExpr::Call(it) => ast::Expr::CallExpr(it),
226                     ast::CallableExpr::MethodCall(it) => ast::Expr::MethodCallExpr(it),
227                 },
228                 replacement,
229             );
230         },
231     )
232 }
233
234 struct CallInfo {
235     node: ast::CallableExpr,
236     arguments: Vec<ast::Expr>,
237     generic_arg_list: Option<ast::GenericArgList>,
238 }
239
240 impl CallInfo {
241     fn from_name_ref(name_ref: ast::NameRef) -> Option<CallInfo> {
242         let parent = name_ref.syntax().parent()?;
243         if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) {
244             let receiver = call.receiver()?;
245             let mut arguments = vec![receiver];
246             arguments.extend(call.arg_list()?.args());
247             Some(CallInfo {
248                 generic_arg_list: call.generic_arg_list(),
249                 node: ast::CallableExpr::MethodCall(call),
250                 arguments,
251             })
252         } else if let Some(segment) = ast::PathSegment::cast(parent) {
253             let path = segment.syntax().parent().and_then(ast::Path::cast)?;
254             let path = path.syntax().parent().and_then(ast::PathExpr::cast)?;
255             let call = path.syntax().parent().and_then(ast::CallExpr::cast)?;
256
257             Some(CallInfo {
258                 arguments: call.arg_list()?.args().collect(),
259                 node: ast::CallableExpr::Call(call),
260                 generic_arg_list: segment.generic_arg_list(),
261             })
262         } else {
263             None
264         }
265     }
266 }
267
268 fn get_fn_params(
269     db: &dyn HirDatabase,
270     function: hir::Function,
271     param_list: &ast::ParamList,
272 ) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param)>> {
273     let mut assoc_fn_params = function.assoc_fn_params(db).into_iter();
274
275     let mut params = Vec::new();
276     if let Some(self_param) = param_list.self_param() {
277         // FIXME this should depend on the receiver as well as the self_param
278         params.push((
279             make::ident_pat(
280                 self_param.amp_token().is_some(),
281                 self_param.mut_token().is_some(),
282                 make::name("this"),
283             )
284             .into(),
285             None,
286             assoc_fn_params.next()?,
287         ));
288     }
289     for param in param_list.params() {
290         params.push((param.pat()?, param.ty(), assoc_fn_params.next()?));
291     }
292
293     Some(params)
294 }
295
296 fn inline(
297     sema: &Semantics<RootDatabase>,
298     function_def_file_id: FileId,
299     function: hir::Function,
300     fn_body: &ast::BlockExpr,
301     params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
302     CallInfo { node, arguments, generic_arg_list }: &CallInfo,
303 ) -> ast::Expr {
304     let body = fn_body.clone_for_update();
305     let usages_for_locals = |local| {
306         Definition::Local(local)
307             .usages(&sema)
308             .all()
309             .references
310             .remove(&function_def_file_id)
311             .unwrap_or_default()
312             .into_iter()
313     };
314     let param_use_nodes: Vec<Vec<_>> = params
315         .iter()
316         .map(|(pat, _, param)| {
317             if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {
318                 return Vec::new();
319             }
320             usages_for_locals(param.as_local(sema.db))
321                 .map(|FileReference { name, range, .. }| match name {
322                     ast::NameLike::NameRef(_) => body
323                         .syntax()
324                         .covering_element(range)
325                         .ancestors()
326                         .nth(3)
327                         .and_then(ast::PathExpr::cast),
328                     _ => None,
329                 })
330                 .collect::<Option<Vec<_>>>()
331                 .unwrap_or_default()
332         })
333         .collect();
334     if function.self_param(sema.db).is_some() {
335         let this = || make::name_ref("this").syntax().clone_for_update();
336         usages_for_locals(params[0].2.as_local(sema.db))
337             .flat_map(|FileReference { name, range, .. }| match name {
338                 ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
339                 _ => None,
340             })
341             .for_each(|it| {
342                 ted::replace(it, &this());
343             })
344     }
345     // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
346     for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
347         let inline_direct = |usage, replacement: &ast::Expr| {
348             if let Some(field) = path_expr_as_record_field(usage) {
349                 cov_mark::hit!(inline_call_inline_direct_field);
350                 field.replace_expr(replacement.clone_for_update());
351             } else {
352                 ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
353             }
354         };
355         // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
356         let usages: &[ast::PathExpr] = &*usages;
357         let expr: &ast::Expr = expr;
358         match usages {
359             // inline single use closure arguments
360             [usage]
361                 if matches!(expr, ast::Expr::ClosureExpr(_))
362                     && usage.syntax().parent().and_then(ast::Expr::cast).is_some() =>
363             {
364                 cov_mark::hit!(inline_call_inline_closure);
365                 let expr = make::expr_paren(expr.clone());
366                 inline_direct(usage, &expr);
367             }
368             // inline single use literals
369             [usage] if matches!(expr, ast::Expr::Literal(_)) => {
370                 cov_mark::hit!(inline_call_inline_literal);
371                 inline_direct(usage, &expr);
372             }
373             // inline direct local arguments
374             [_, ..] if expr_as_name_ref(&expr).is_some() => {
375                 cov_mark::hit!(inline_call_inline_locals);
376                 usages.into_iter().for_each(|usage| inline_direct(usage, &expr));
377             }
378             // can't inline, emit a let statement
379             _ => {
380                 let ty =
381                     sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
382                 if let Some(stmt_list) = body.stmt_list() {
383                     stmt_list.push_front(
384                         make::let_stmt(pat.clone(), ty, Some(expr.clone()))
385                             .clone_for_update()
386                             .into(),
387                     )
388                 }
389             }
390         }
391     }
392     if let Some(generic_arg_list) = generic_arg_list.clone() {
393         PathTransform::function_call(
394             &sema.scope(node.syntax()),
395             &sema.scope(fn_body.syntax()),
396             function,
397             generic_arg_list,
398         )
399         .apply(body.syntax());
400     }
401
402     let original_indentation = match node {
403         ast::CallableExpr::Call(it) => it.indent_level(),
404         ast::CallableExpr::MethodCall(it) => it.indent_level(),
405     };
406     body.reindent_to(original_indentation);
407
408     match body.tail_expr() {
409         Some(expr) if body.statements().next().is_none() => expr,
410         _ => match node
411             .syntax()
412             .parent()
413             .and_then(ast::BinExpr::cast)
414             .and_then(|bin_expr| bin_expr.lhs())
415         {
416             Some(lhs) if lhs.syntax() == node.syntax() => {
417                 make::expr_paren(ast::Expr::BlockExpr(body)).clone_for_update()
418             }
419             _ => ast::Expr::BlockExpr(body),
420         },
421     }
422 }
423
424 fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {
425     let path = usage.path()?;
426     let name_ref = path.as_single_name_ref()?;
427     ast::RecordExprField::for_name_ref(&name_ref)
428 }
429
430 #[cfg(test)]
431 mod tests {
432     use crate::tests::{check_assist, check_assist_not_applicable};
433
434     use super::*;
435
436     #[test]
437     fn no_args_or_return_value_gets_inlined_without_block() {
438         check_assist(
439             inline_call,
440             r#"
441 fn foo() { println!("Hello, World!"); }
442 fn main() {
443     fo$0o();
444 }
445 "#,
446             r#"
447 fn foo() { println!("Hello, World!"); }
448 fn main() {
449     { println!("Hello, World!"); };
450 }
451 "#,
452         );
453     }
454
455     #[test]
456     fn not_applicable_when_incorrect_number_of_parameters_are_provided() {
457         cov_mark::check!(inline_call_incorrect_number_of_arguments);
458         check_assist_not_applicable(
459             inline_call,
460             r#"
461 fn add(a: u32, b: u32) -> u32 { a + b }
462 fn main() { let x = add$0(42); }
463 "#,
464         );
465     }
466
467     #[test]
468     fn args_with_side_effects() {
469         check_assist(
470             inline_call,
471             r#"
472 fn foo(name: String) {
473     println!("Hello, {}!", name);
474 }
475 fn main() {
476     foo$0(String::from("Michael"));
477 }
478 "#,
479             r#"
480 fn foo(name: String) {
481     println!("Hello, {}!", name);
482 }
483 fn main() {
484     {
485         let name = String::from("Michael");
486         println!("Hello, {}!", name);
487     };
488 }
489 "#,
490         );
491     }
492
493     #[test]
494     fn function_with_multiple_statements() {
495         check_assist(
496             inline_call,
497             r#"
498 fn foo(a: u32, b: u32) -> u32 {
499     let x = a + b;
500     let y = x - b;
501     x * y
502 }
503
504 fn main() {
505     let x = foo$0(1, 2);
506 }
507 "#,
508             r#"
509 fn foo(a: u32, b: u32) -> u32 {
510     let x = a + b;
511     let y = x - b;
512     x * y
513 }
514
515 fn main() {
516     let x = {
517         let b = 2;
518         let x = 1 + b;
519         let y = x - b;
520         x * y
521     };
522 }
523 "#,
524         );
525     }
526
527     #[test]
528     fn function_with_self_param() {
529         check_assist(
530             inline_call,
531             r#"
532 struct Foo(u32);
533
534 impl Foo {
535     fn add(self, a: u32) -> Self {
536         Foo(self.0 + a)
537     }
538 }
539
540 fn main() {
541     let x = Foo::add$0(Foo(3), 2);
542 }
543 "#,
544             r#"
545 struct Foo(u32);
546
547 impl Foo {
548     fn add(self, a: u32) -> Self {
549         Foo(self.0 + a)
550     }
551 }
552
553 fn main() {
554     let x = {
555         let this = Foo(3);
556         Foo(this.0 + 2)
557     };
558 }
559 "#,
560         );
561     }
562
563     #[test]
564     fn method_by_val() {
565         check_assist(
566             inline_call,
567             r#"
568 struct Foo(u32);
569
570 impl Foo {
571     fn add(self, a: u32) -> Self {
572         Foo(self.0 + a)
573     }
574 }
575
576 fn main() {
577     let x = Foo(3).add$0(2);
578 }
579 "#,
580             r#"
581 struct Foo(u32);
582
583 impl Foo {
584     fn add(self, a: u32) -> Self {
585         Foo(self.0 + a)
586     }
587 }
588
589 fn main() {
590     let x = {
591         let this = Foo(3);
592         Foo(this.0 + 2)
593     };
594 }
595 "#,
596         );
597     }
598
599     #[test]
600     fn method_by_ref() {
601         check_assist(
602             inline_call,
603             r#"
604 struct Foo(u32);
605
606 impl Foo {
607     fn add(&self, a: u32) -> Self {
608         Foo(self.0 + a)
609     }
610 }
611
612 fn main() {
613     let x = Foo(3).add$0(2);
614 }
615 "#,
616             r#"
617 struct Foo(u32);
618
619 impl Foo {
620     fn add(&self, a: u32) -> Self {
621         Foo(self.0 + a)
622     }
623 }
624
625 fn main() {
626     let x = {
627         let ref this = Foo(3);
628         Foo(this.0 + 2)
629     };
630 }
631 "#,
632         );
633     }
634
635     #[test]
636     fn method_by_ref_mut() {
637         check_assist(
638             inline_call,
639             r#"
640 struct Foo(u32);
641
642 impl Foo {
643     fn clear(&mut self) {
644         self.0 = 0;
645     }
646 }
647
648 fn main() {
649     let mut foo = Foo(3);
650     foo.clear$0();
651 }
652 "#,
653             r#"
654 struct Foo(u32);
655
656 impl Foo {
657     fn clear(&mut self) {
658         self.0 = 0;
659     }
660 }
661
662 fn main() {
663     let mut foo = Foo(3);
664     {
665         let ref mut this = foo;
666         this.0 = 0;
667     };
668 }
669 "#,
670         );
671     }
672
673     #[test]
674     fn function_multi_use_expr_in_param() {
675         check_assist(
676             inline_call,
677             r#"
678 fn square(x: u32) -> u32 {
679     x * x
680 }
681 fn main() {
682     let x = 51;
683     let y = square$0(10 + x);
684 }
685 "#,
686             r#"
687 fn square(x: u32) -> u32 {
688     x * x
689 }
690 fn main() {
691     let x = 51;
692     let y = {
693         let x = 10 + x;
694         x * x
695     };
696 }
697 "#,
698         );
699     }
700
701     #[test]
702     fn function_use_local_in_param() {
703         cov_mark::check!(inline_call_inline_locals);
704         check_assist(
705             inline_call,
706             r#"
707 fn square(x: u32) -> u32 {
708     x * x
709 }
710 fn main() {
711     let local = 51;
712     let y = square$0(local);
713 }
714 "#,
715             r#"
716 fn square(x: u32) -> u32 {
717     x * x
718 }
719 fn main() {
720     let local = 51;
721     let y = local * local;
722 }
723 "#,
724         );
725     }
726
727     #[test]
728     fn method_in_impl() {
729         check_assist(
730             inline_call,
731             r#"
732 struct Foo;
733 impl Foo {
734     fn foo(&self) {
735         self;
736         self;
737     }
738     fn bar(&self) {
739         self.foo$0();
740     }
741 }
742 "#,
743             r#"
744 struct Foo;
745 impl Foo {
746     fn foo(&self) {
747         self;
748         self;
749     }
750     fn bar(&self) {
751         {
752             let ref this = self;
753             this;
754             this;
755         };
756     }
757 }
758 "#,
759         );
760     }
761
762     #[test]
763     fn wraps_closure_in_paren() {
764         cov_mark::check!(inline_call_inline_closure);
765         check_assist(
766             inline_call,
767             r#"
768 fn foo(x: fn()) {
769     x();
770 }
771
772 fn main() {
773     foo$0(|| {})
774 }
775 "#,
776             r#"
777 fn foo(x: fn()) {
778     x();
779 }
780
781 fn main() {
782     {
783         (|| {})();
784     }
785 }
786 "#,
787         );
788         check_assist(
789             inline_call,
790             r#"
791 fn foo(x: fn()) {
792     x();
793 }
794
795 fn main() {
796     foo$0(main)
797 }
798 "#,
799             r#"
800 fn foo(x: fn()) {
801     x();
802 }
803
804 fn main() {
805     {
806         main();
807     }
808 }
809 "#,
810         );
811     }
812
813     #[test]
814     fn inline_single_literal_expr() {
815         cov_mark::check!(inline_call_inline_literal);
816         check_assist(
817             inline_call,
818             r#"
819 fn foo(x: u32) -> u32{
820     x
821 }
822
823 fn main() {
824     foo$0(222);
825 }
826 "#,
827             r#"
828 fn foo(x: u32) -> u32{
829     x
830 }
831
832 fn main() {
833     222;
834 }
835 "#,
836         );
837     }
838
839     #[test]
840     fn inline_emits_type_for_coercion() {
841         check_assist(
842             inline_call,
843             r#"
844 fn foo(x: *const u32) -> u32 {
845     x as u32
846 }
847
848 fn main() {
849     foo$0(&222);
850 }
851 "#,
852             r#"
853 fn foo(x: *const u32) -> u32 {
854     x as u32
855 }
856
857 fn main() {
858     {
859         let x: *const u32 = &222;
860         x as u32
861     };
862 }
863 "#,
864         );
865     }
866
867     // FIXME: const generics aren't being substituted, this is blocked on better support for them
868     #[test]
869     fn inline_substitutes_generics() {
870         check_assist(
871             inline_call,
872             r#"
873 fn foo<T, const N: usize>() {
874     bar::<T, N>()
875 }
876
877 fn bar<U, const M: usize>() {}
878
879 fn main() {
880     foo$0::<usize, {0}>();
881 }
882 "#,
883             r#"
884 fn foo<T, const N: usize>() {
885     bar::<T, N>()
886 }
887
888 fn bar<U, const M: usize>() {}
889
890 fn main() {
891     bar::<usize, N>();
892 }
893 "#,
894         );
895     }
896
897     #[test]
898     fn inline_callers() {
899         check_assist(
900             inline_into_callers,
901             r#"
902 fn do_the_math$0(b: u32) -> u32 {
903     let foo = 10;
904     foo * b + foo
905 }
906 fn foo() {
907     do_the_math(0);
908     let bar = 10;
909     do_the_math(bar);
910 }
911 "#,
912             r#"
913
914 fn foo() {
915     {
916         let foo = 10;
917         foo * 0 + foo
918     };
919     let bar = 10;
920     {
921         let foo = 10;
922         foo * bar + foo
923     };
924 }
925 "#,
926         );
927     }
928
929     #[test]
930     fn inline_callers_across_files() {
931         check_assist(
932             inline_into_callers,
933             r#"
934 //- /lib.rs
935 mod foo;
936 fn do_the_math$0(b: u32) -> u32 {
937     let foo = 10;
938     foo * b + foo
939 }
940 //- /foo.rs
941 use super::do_the_math;
942 fn foo() {
943     do_the_math(0);
944     let bar = 10;
945     do_the_math(bar);
946 }
947 "#,
948             r#"
949 //- /lib.rs
950 mod foo;
951
952 //- /foo.rs
953 fn foo() {
954     {
955         let foo = 10;
956         foo * 0 + foo
957     };
958     let bar = 10;
959     {
960         let foo = 10;
961         foo * bar + foo
962     };
963 }
964 "#,
965         );
966     }
967
968     #[test]
969     fn inline_callers_across_files_with_def_file() {
970         check_assist(
971             inline_into_callers,
972             r#"
973 //- /lib.rs
974 mod foo;
975 fn do_the_math$0(b: u32) -> u32 {
976     let foo = 10;
977     foo * b + foo
978 }
979 fn bar(a: u32, b: u32) -> u32 {
980     do_the_math(0);
981 }
982 //- /foo.rs
983 use super::do_the_math;
984 fn foo() {
985     do_the_math(0);
986 }
987 "#,
988             r#"
989 //- /lib.rs
990 mod foo;
991
992 fn bar(a: u32, b: u32) -> u32 {
993     {
994         let foo = 10;
995         foo * 0 + foo
996     };
997 }
998 //- /foo.rs
999 fn foo() {
1000     {
1001         let foo = 10;
1002         foo * 0 + foo
1003     };
1004 }
1005 "#,
1006         );
1007     }
1008
1009     #[test]
1010     fn inline_callers_recursive() {
1011         cov_mark::check!(inline_into_callers_recursive);
1012         check_assist_not_applicable(
1013             inline_into_callers,
1014             r#"
1015 fn foo$0() {
1016     foo();
1017 }
1018 "#,
1019         );
1020     }
1021
1022     #[test]
1023     fn inline_call_recursive() {
1024         cov_mark::check!(inline_call_recursive);
1025         check_assist_not_applicable(
1026             inline_call,
1027             r#"
1028 fn foo() {
1029     foo$0();
1030 }
1031 "#,
1032         );
1033     }
1034
1035     #[test]
1036     fn inline_call_field_shorthand() {
1037         cov_mark::check!(inline_call_inline_direct_field);
1038         check_assist(
1039             inline_call,
1040             r#"
1041 struct Foo {
1042     field: u32,
1043     field1: u32,
1044     field2: u32,
1045     field3: u32,
1046 }
1047 fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1048     Foo {
1049         field,
1050         field1,
1051         field2: val2,
1052         field3: val3,
1053     }
1054 }
1055 fn main() {
1056     let bar = 0;
1057     let baz = 0;
1058     foo$0(bar, 0, baz, 0);
1059 }
1060 "#,
1061             r#"
1062 struct Foo {
1063     field: u32,
1064     field1: u32,
1065     field2: u32,
1066     field3: u32,
1067 }
1068 fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1069     Foo {
1070         field,
1071         field1,
1072         field2: val2,
1073         field3: val3,
1074     }
1075 }
1076 fn main() {
1077     let bar = 0;
1078     let baz = 0;
1079     Foo {
1080             field: bar,
1081             field1: 0,
1082             field2: baz,
1083             field3: 0,
1084         };
1085 }
1086 "#,
1087         );
1088     }
1089
1090     #[test]
1091     fn inline_callers_wrapped_in_parentheses() {
1092         check_assist(
1093             inline_into_callers,
1094             r#"
1095 fn foo$0() -> u32 {
1096     let x = 0;
1097     x
1098 }
1099 fn bar() -> u32 {
1100     foo() + foo()
1101 }
1102 "#,
1103             r#"
1104
1105 fn bar() -> u32 {
1106     ({
1107         let x = 0;
1108         x
1109     }) + {
1110         let x = 0;
1111         x
1112     }
1113 }
1114 "#,
1115         )
1116     }
1117
1118     #[test]
1119     fn inline_call_wrapped_in_parentheses() {
1120         check_assist(
1121             inline_call,
1122             r#"
1123 fn foo() -> u32 {
1124     let x = 0;
1125     x
1126 }
1127 fn bar() -> u32 {
1128     foo$0() + foo()
1129 }
1130 "#,
1131             r#"
1132 fn foo() -> u32 {
1133     let x = 0;
1134     x
1135 }
1136 fn bar() -> u32 {
1137     ({
1138         let x = 0;
1139         x
1140     }) + foo()
1141 }
1142 "#,
1143         )
1144     }
1145 }