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