]> git.lizzy.rs Git - rust.git/blob - crates/ide-assists/src/handlers/inline_call.rs
fix: Insert spaces when inlining a function defined in a macro.
[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::{insert_whitespace_into_node::insert_ws_into, 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 = if sema.hir_file_for(fn_body.syntax()).is_macro() {
305         cov_mark::hit!(inline_call_defined_in_macro);
306         if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
307             body
308         } else {
309             // FIXME(zachs18): I believe this should be unreachable,
310             // since insert_ws_into shouldn't change the kind of the SyntaxNode.
311             fn_body.clone_for_update()
312         }
313     } else {
314         fn_body.clone_for_update()
315     };
316     let usages_for_locals = |local| {
317         Definition::Local(local)
318             .usages(sema)
319             .all()
320             .references
321             .remove(&function_def_file_id)
322             .unwrap_or_default()
323             .into_iter()
324     };
325     let param_use_nodes: Vec<Vec<_>> = params
326         .iter()
327         .map(|(pat, _, param)| {
328             if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {
329                 return Vec::new();
330             }
331             // FIXME: we need to fetch all locals declared in the parameter here
332             // not only the local if it is a simple binding
333             match param.as_local(sema.db) {
334                 Some(l) => usages_for_locals(l)
335                     .map(|FileReference { name, range, .. }| match name {
336                         ast::NameLike::NameRef(_) => body
337                             .syntax()
338                             .covering_element(range)
339                             .ancestors()
340                             .nth(3)
341                             .and_then(ast::PathExpr::cast),
342                         _ => None,
343                     })
344                     .collect::<Option<Vec<_>>>()
345                     .unwrap_or_default(),
346                 None => Vec::new(),
347             }
348         })
349         .collect();
350     if function.self_param(sema.db).is_some() {
351         let this = || make::name_ref("this").syntax().clone_for_update();
352         if let Some(self_local) = params[0].2.as_local(sema.db) {
353             usages_for_locals(self_local)
354                 .flat_map(|FileReference { name, range, .. }| match name {
355                     ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
356                     _ => None,
357                 })
358                 .for_each(|it| {
359                     ted::replace(it, &this());
360                 })
361         }
362     }
363     // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
364     for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
365         let inline_direct = |usage, replacement: &ast::Expr| {
366             if let Some(field) = path_expr_as_record_field(usage) {
367                 cov_mark::hit!(inline_call_inline_direct_field);
368                 field.replace_expr(replacement.clone_for_update());
369             } else {
370                 ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
371             }
372         };
373         // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
374         let usages: &[ast::PathExpr] = &*usages;
375         let expr: &ast::Expr = expr;
376         match usages {
377             // inline single use closure arguments
378             [usage]
379                 if matches!(expr, ast::Expr::ClosureExpr(_))
380                     && usage.syntax().parent().and_then(ast::Expr::cast).is_some() =>
381             {
382                 cov_mark::hit!(inline_call_inline_closure);
383                 let expr = make::expr_paren(expr.clone());
384                 inline_direct(usage, &expr);
385             }
386             // inline single use literals
387             [usage] if matches!(expr, ast::Expr::Literal(_)) => {
388                 cov_mark::hit!(inline_call_inline_literal);
389                 inline_direct(usage, expr);
390             }
391             // inline direct local arguments
392             [_, ..] if expr_as_name_ref(expr).is_some() => {
393                 cov_mark::hit!(inline_call_inline_locals);
394                 usages.iter().for_each(|usage| inline_direct(usage, expr));
395             }
396             // can't inline, emit a let statement
397             _ => {
398                 let ty =
399                     sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
400                 if let Some(stmt_list) = body.stmt_list() {
401                     stmt_list.push_front(
402                         make::let_stmt(pat.clone(), ty, Some(expr.clone()))
403                             .clone_for_update()
404                             .into(),
405                     )
406                 }
407             }
408         }
409     }
410     if let Some(generic_arg_list) = generic_arg_list.clone() {
411         if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
412         {
413             PathTransform::function_call(target, source, function, generic_arg_list)
414                 .apply(body.syntax());
415         }
416     }
417
418     let original_indentation = match node {
419         ast::CallableExpr::Call(it) => it.indent_level(),
420         ast::CallableExpr::MethodCall(it) => it.indent_level(),
421     };
422     body.reindent_to(original_indentation);
423
424     match body.tail_expr() {
425         Some(expr) if body.statements().next().is_none() => expr,
426         _ => match node
427             .syntax()
428             .parent()
429             .and_then(ast::BinExpr::cast)
430             .and_then(|bin_expr| bin_expr.lhs())
431         {
432             Some(lhs) if lhs.syntax() == node.syntax() => {
433                 make::expr_paren(ast::Expr::BlockExpr(body)).clone_for_update()
434             }
435             _ => ast::Expr::BlockExpr(body),
436         },
437     }
438 }
439
440 fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {
441     let path = usage.path()?;
442     let name_ref = path.as_single_name_ref()?;
443     ast::RecordExprField::for_name_ref(&name_ref)
444 }
445
446 #[cfg(test)]
447 mod tests {
448     use crate::tests::{check_assist, check_assist_not_applicable};
449
450     use super::*;
451
452     #[test]
453     fn no_args_or_return_value_gets_inlined_without_block() {
454         check_assist(
455             inline_call,
456             r#"
457 fn foo() { println!("Hello, World!"); }
458 fn main() {
459     fo$0o();
460 }
461 "#,
462             r#"
463 fn foo() { println!("Hello, World!"); }
464 fn main() {
465     { println!("Hello, World!"); };
466 }
467 "#,
468         );
469     }
470
471     #[test]
472     fn not_applicable_when_incorrect_number_of_parameters_are_provided() {
473         cov_mark::check!(inline_call_incorrect_number_of_arguments);
474         check_assist_not_applicable(
475             inline_call,
476             r#"
477 fn add(a: u32, b: u32) -> u32 { a + b }
478 fn main() { let x = add$0(42); }
479 "#,
480         );
481     }
482
483     #[test]
484     fn args_with_side_effects() {
485         check_assist(
486             inline_call,
487             r#"
488 fn foo(name: String) {
489     println!("Hello, {}!", name);
490 }
491 fn main() {
492     foo$0(String::from("Michael"));
493 }
494 "#,
495             r#"
496 fn foo(name: String) {
497     println!("Hello, {}!", name);
498 }
499 fn main() {
500     {
501         let name = String::from("Michael");
502         println!("Hello, {}!", name);
503     };
504 }
505 "#,
506         );
507     }
508
509     #[test]
510     fn function_with_multiple_statements() {
511         check_assist(
512             inline_call,
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 = foo$0(1, 2);
522 }
523 "#,
524             r#"
525 fn foo(a: u32, b: u32) -> u32 {
526     let x = a + b;
527     let y = x - b;
528     x * y
529 }
530
531 fn main() {
532     let x = {
533         let b = 2;
534         let x = 1 + b;
535         let y = x - b;
536         x * y
537     };
538 }
539 "#,
540         );
541     }
542
543     #[test]
544     fn function_with_self_param() {
545         check_assist(
546             inline_call,
547             r#"
548 struct Foo(u32);
549
550 impl Foo {
551     fn add(self, a: u32) -> Self {
552         Foo(self.0 + a)
553     }
554 }
555
556 fn main() {
557     let x = Foo::add$0(Foo(3), 2);
558 }
559 "#,
560             r#"
561 struct Foo(u32);
562
563 impl Foo {
564     fn add(self, a: u32) -> Self {
565         Foo(self.0 + a)
566     }
567 }
568
569 fn main() {
570     let x = {
571         let this = Foo(3);
572         Foo(this.0 + 2)
573     };
574 }
575 "#,
576         );
577     }
578
579     #[test]
580     fn method_by_val() {
581         check_assist(
582             inline_call,
583             r#"
584 struct Foo(u32);
585
586 impl Foo {
587     fn add(self, a: u32) -> Self {
588         Foo(self.0 + a)
589     }
590 }
591
592 fn main() {
593     let x = Foo(3).add$0(2);
594 }
595 "#,
596             r#"
597 struct Foo(u32);
598
599 impl Foo {
600     fn add(self, a: u32) -> Self {
601         Foo(self.0 + a)
602     }
603 }
604
605 fn main() {
606     let x = {
607         let this = Foo(3);
608         Foo(this.0 + 2)
609     };
610 }
611 "#,
612         );
613     }
614
615     #[test]
616     fn method_by_ref() {
617         check_assist(
618             inline_call,
619             r#"
620 struct Foo(u32);
621
622 impl Foo {
623     fn add(&self, a: u32) -> Self {
624         Foo(self.0 + a)
625     }
626 }
627
628 fn main() {
629     let x = Foo(3).add$0(2);
630 }
631 "#,
632             r#"
633 struct Foo(u32);
634
635 impl Foo {
636     fn add(&self, a: u32) -> Self {
637         Foo(self.0 + a)
638     }
639 }
640
641 fn main() {
642     let x = {
643         let ref this = Foo(3);
644         Foo(this.0 + 2)
645     };
646 }
647 "#,
648         );
649     }
650
651     #[test]
652     fn method_by_ref_mut() {
653         check_assist(
654             inline_call,
655             r#"
656 struct Foo(u32);
657
658 impl Foo {
659     fn clear(&mut self) {
660         self.0 = 0;
661     }
662 }
663
664 fn main() {
665     let mut foo = Foo(3);
666     foo.clear$0();
667 }
668 "#,
669             r#"
670 struct Foo(u32);
671
672 impl Foo {
673     fn clear(&mut self) {
674         self.0 = 0;
675     }
676 }
677
678 fn main() {
679     let mut foo = Foo(3);
680     {
681         let ref mut this = foo;
682         this.0 = 0;
683     };
684 }
685 "#,
686         );
687     }
688
689     #[test]
690     fn function_multi_use_expr_in_param() {
691         check_assist(
692             inline_call,
693             r#"
694 fn square(x: u32) -> u32 {
695     x * x
696 }
697 fn main() {
698     let x = 51;
699     let y = square$0(10 + x);
700 }
701 "#,
702             r#"
703 fn square(x: u32) -> u32 {
704     x * x
705 }
706 fn main() {
707     let x = 51;
708     let y = {
709         let x = 10 + x;
710         x * x
711     };
712 }
713 "#,
714         );
715     }
716
717     #[test]
718     fn function_use_local_in_param() {
719         cov_mark::check!(inline_call_inline_locals);
720         check_assist(
721             inline_call,
722             r#"
723 fn square(x: u32) -> u32 {
724     x * x
725 }
726 fn main() {
727     let local = 51;
728     let y = square$0(local);
729 }
730 "#,
731             r#"
732 fn square(x: u32) -> u32 {
733     x * x
734 }
735 fn main() {
736     let local = 51;
737     let y = local * local;
738 }
739 "#,
740         );
741     }
742
743     #[test]
744     fn method_in_impl() {
745         check_assist(
746             inline_call,
747             r#"
748 struct Foo;
749 impl Foo {
750     fn foo(&self) {
751         self;
752         self;
753     }
754     fn bar(&self) {
755         self.foo$0();
756     }
757 }
758 "#,
759             r#"
760 struct Foo;
761 impl Foo {
762     fn foo(&self) {
763         self;
764         self;
765     }
766     fn bar(&self) {
767         {
768             let ref this = self;
769             this;
770             this;
771         };
772     }
773 }
774 "#,
775         );
776     }
777
778     #[test]
779     fn wraps_closure_in_paren() {
780         cov_mark::check!(inline_call_inline_closure);
781         check_assist(
782             inline_call,
783             r#"
784 fn foo(x: fn()) {
785     x();
786 }
787
788 fn main() {
789     foo$0(|| {})
790 }
791 "#,
792             r#"
793 fn foo(x: fn()) {
794     x();
795 }
796
797 fn main() {
798     {
799         (|| {})();
800     }
801 }
802 "#,
803         );
804         check_assist(
805             inline_call,
806             r#"
807 fn foo(x: fn()) {
808     x();
809 }
810
811 fn main() {
812     foo$0(main)
813 }
814 "#,
815             r#"
816 fn foo(x: fn()) {
817     x();
818 }
819
820 fn main() {
821     {
822         main();
823     }
824 }
825 "#,
826         );
827     }
828
829     #[test]
830     fn inline_single_literal_expr() {
831         cov_mark::check!(inline_call_inline_literal);
832         check_assist(
833             inline_call,
834             r#"
835 fn foo(x: u32) -> u32{
836     x
837 }
838
839 fn main() {
840     foo$0(222);
841 }
842 "#,
843             r#"
844 fn foo(x: u32) -> u32{
845     x
846 }
847
848 fn main() {
849     222;
850 }
851 "#,
852         );
853     }
854
855     #[test]
856     fn inline_emits_type_for_coercion() {
857         check_assist(
858             inline_call,
859             r#"
860 fn foo(x: *const u32) -> u32 {
861     x as u32
862 }
863
864 fn main() {
865     foo$0(&222);
866 }
867 "#,
868             r#"
869 fn foo(x: *const u32) -> u32 {
870     x as u32
871 }
872
873 fn main() {
874     {
875         let x: *const u32 = &222;
876         x as u32
877     };
878 }
879 "#,
880         );
881     }
882
883     // FIXME: const generics aren't being substituted, this is blocked on better support for them
884     #[test]
885     fn inline_substitutes_generics() {
886         check_assist(
887             inline_call,
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     foo$0::<usize, {0}>();
897 }
898 "#,
899             r#"
900 fn foo<T, const N: usize>() {
901     bar::<T, N>()
902 }
903
904 fn bar<U, const M: usize>() {}
905
906 fn main() {
907     bar::<usize, N>();
908 }
909 "#,
910         );
911     }
912
913     #[test]
914     fn inline_callers() {
915         check_assist(
916             inline_into_callers,
917             r#"
918 fn do_the_math$0(b: u32) -> u32 {
919     let foo = 10;
920     foo * b + foo
921 }
922 fn foo() {
923     do_the_math(0);
924     let bar = 10;
925     do_the_math(bar);
926 }
927 "#,
928             r#"
929
930 fn foo() {
931     {
932         let foo = 10;
933         foo * 0 + foo
934     };
935     let bar = 10;
936     {
937         let foo = 10;
938         foo * bar + foo
939     };
940 }
941 "#,
942         );
943     }
944
945     #[test]
946     fn inline_callers_across_files() {
947         check_assist(
948             inline_into_callers,
949             r#"
950 //- /lib.rs
951 mod foo;
952 fn do_the_math$0(b: u32) -> u32 {
953     let foo = 10;
954     foo * b + foo
955 }
956 //- /foo.rs
957 use super::do_the_math;
958 fn foo() {
959     do_the_math(0);
960     let bar = 10;
961     do_the_math(bar);
962 }
963 "#,
964             r#"
965 //- /lib.rs
966 mod foo;
967
968 //- /foo.rs
969 fn foo() {
970     {
971         let foo = 10;
972         foo * 0 + foo
973     };
974     let bar = 10;
975     {
976         let foo = 10;
977         foo * bar + foo
978     };
979 }
980 "#,
981         );
982     }
983
984     #[test]
985     fn inline_callers_across_files_with_def_file() {
986         check_assist(
987             inline_into_callers,
988             r#"
989 //- /lib.rs
990 mod foo;
991 fn do_the_math$0(b: u32) -> u32 {
992     let foo = 10;
993     foo * b + foo
994 }
995 fn bar(a: u32, b: u32) -> u32 {
996     do_the_math(0);
997 }
998 //- /foo.rs
999 use super::do_the_math;
1000 fn foo() {
1001     do_the_math(0);
1002 }
1003 "#,
1004             r#"
1005 //- /lib.rs
1006 mod foo;
1007
1008 fn bar(a: u32, b: u32) -> u32 {
1009     {
1010         let foo = 10;
1011         foo * 0 + foo
1012     };
1013 }
1014 //- /foo.rs
1015 fn foo() {
1016     {
1017         let foo = 10;
1018         foo * 0 + foo
1019     };
1020 }
1021 "#,
1022         );
1023     }
1024
1025     #[test]
1026     fn inline_callers_recursive() {
1027         cov_mark::check!(inline_into_callers_recursive);
1028         check_assist_not_applicable(
1029             inline_into_callers,
1030             r#"
1031 fn foo$0() {
1032     foo();
1033 }
1034 "#,
1035         );
1036     }
1037
1038     #[test]
1039     fn inline_call_recursive() {
1040         cov_mark::check!(inline_call_recursive);
1041         check_assist_not_applicable(
1042             inline_call,
1043             r#"
1044 fn foo() {
1045     foo$0();
1046 }
1047 "#,
1048         );
1049     }
1050
1051     #[test]
1052     fn inline_call_field_shorthand() {
1053         cov_mark::check!(inline_call_inline_direct_field);
1054         check_assist(
1055             inline_call,
1056             r#"
1057 struct Foo {
1058     field: u32,
1059     field1: u32,
1060     field2: u32,
1061     field3: u32,
1062 }
1063 fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1064     Foo {
1065         field,
1066         field1,
1067         field2: val2,
1068         field3: val3,
1069     }
1070 }
1071 fn main() {
1072     let bar = 0;
1073     let baz = 0;
1074     foo$0(bar, 0, baz, 0);
1075 }
1076 "#,
1077             r#"
1078 struct Foo {
1079     field: u32,
1080     field1: u32,
1081     field2: u32,
1082     field3: u32,
1083 }
1084 fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1085     Foo {
1086         field,
1087         field1,
1088         field2: val2,
1089         field3: val3,
1090     }
1091 }
1092 fn main() {
1093     let bar = 0;
1094     let baz = 0;
1095     Foo {
1096             field: bar,
1097             field1: 0,
1098             field2: baz,
1099             field3: 0,
1100         };
1101 }
1102 "#,
1103         );
1104     }
1105
1106     #[test]
1107     fn inline_callers_wrapped_in_parentheses() {
1108         check_assist(
1109             inline_into_callers,
1110             r#"
1111 fn foo$0() -> u32 {
1112     let x = 0;
1113     x
1114 }
1115 fn bar() -> u32 {
1116     foo() + foo()
1117 }
1118 "#,
1119             r#"
1120
1121 fn bar() -> u32 {
1122     ({
1123         let x = 0;
1124         x
1125     }) + {
1126         let x = 0;
1127         x
1128     }
1129 }
1130 "#,
1131         )
1132     }
1133
1134     #[test]
1135     fn inline_call_wrapped_in_parentheses() {
1136         check_assist(
1137             inline_call,
1138             r#"
1139 fn foo() -> u32 {
1140     let x = 0;
1141     x
1142 }
1143 fn bar() -> u32 {
1144     foo$0() + foo()
1145 }
1146 "#,
1147             r#"
1148 fn foo() -> u32 {
1149     let x = 0;
1150     x
1151 }
1152 fn bar() -> u32 {
1153     ({
1154         let x = 0;
1155         x
1156     }) + foo()
1157 }
1158 "#,
1159         )
1160     }
1161
1162     #[test]
1163     fn inline_call_defined_in_macro() {
1164         cov_mark::check!(inline_call_defined_in_macro);
1165         check_assist(
1166             inline_call,
1167             r#"
1168 macro_rules! define_foo {
1169     () => { fn foo() -> u32 {
1170         let x = 0;
1171         x
1172     } };
1173 }
1174 define_foo!();
1175 fn bar() -> u32 {
1176     foo$0()
1177 }
1178 "#,
1179             r#"
1180 macro_rules! define_foo {
1181     () => { fn foo() -> u32 {
1182         let x = 0;
1183         x
1184     } };
1185 }
1186 define_foo!();
1187 fn bar() -> u32 {
1188     {
1189       let x = 0;
1190       x
1191     }
1192 }
1193 "#,
1194         )
1195     }
1196 }