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