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