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