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