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