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