• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // ```
inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>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 
split_refs_and_uses<T: ast::AstNode>( builder: &mut SourceChangeBuilder, iter: impl IntoIterator<Item = FileReference>, mut map_ref: impl FnMut(ast::NameRef) -> Option<T>, ) -> (Vec<T>, Vec<ast::Path>)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 // ```
inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>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 {
from_name_ref(name_ref: ast::NameRef) -> Option<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 
get_fn_params( db: &dyn HirDatabase, function: hir::Function, param_list: &ast::ParamList, ) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param)>>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().first_token().unwrap();
367         if let Some(self_local) = params[0].2.as_local(sema.db) {
368             usages_for_locals(self_local)
369                 .filter_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 
path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField>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]
no_args_or_return_value_gets_inlined_without_block()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]
not_applicable_when_incorrect_number_of_parameters_are_provided()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]
args_with_side_effects()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]
function_with_multiple_statements()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]
function_with_self_param()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]
method_by_val()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]
method_by_ref()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]
generic_method_by_ref()694     fn generic_method_by_ref() {
695         check_assist(
696             inline_call,
697             r#"
698 struct Foo(u32);
699 
700 impl Foo {
701     fn add<T>(&self, a: u32) -> Self {
702         Foo(self.0 + a)
703     }
704 }
705 
706 fn main() {
707     let x = Foo(3).add$0::<usize>(2);
708 }
709 "#,
710             r#"
711 struct Foo(u32);
712 
713 impl Foo {
714     fn add<T>(&self, a: u32) -> Self {
715         Foo(self.0 + a)
716     }
717 }
718 
719 fn main() {
720     let x = {
721         let ref this = Foo(3);
722         Foo(this.0 + 2)
723     };
724 }
725 "#,
726         );
727     }
728 
729     #[test]
method_by_ref_mut()730     fn method_by_ref_mut() {
731         check_assist(
732             inline_call,
733             r#"
734 struct Foo(u32);
735 
736 impl Foo {
737     fn clear(&mut self) {
738         self.0 = 0;
739     }
740 }
741 
742 fn main() {
743     let mut foo = Foo(3);
744     foo.clear$0();
745 }
746 "#,
747             r#"
748 struct Foo(u32);
749 
750 impl Foo {
751     fn clear(&mut self) {
752         self.0 = 0;
753     }
754 }
755 
756 fn main() {
757     let mut foo = Foo(3);
758     {
759         let ref mut this = foo;
760         this.0 = 0;
761     };
762 }
763 "#,
764         );
765     }
766 
767     #[test]
function_multi_use_expr_in_param()768     fn function_multi_use_expr_in_param() {
769         check_assist(
770             inline_call,
771             r#"
772 fn square(x: u32) -> u32 {
773     x * x
774 }
775 fn main() {
776     let x = 51;
777     let y = square$0(10 + x);
778 }
779 "#,
780             r#"
781 fn square(x: u32) -> u32 {
782     x * x
783 }
784 fn main() {
785     let x = 51;
786     let y = {
787         let x = 10 + x;
788         x * x
789     };
790 }
791 "#,
792         );
793     }
794 
795     #[test]
function_use_local_in_param()796     fn function_use_local_in_param() {
797         cov_mark::check!(inline_call_inline_locals);
798         check_assist(
799             inline_call,
800             r#"
801 fn square(x: u32) -> u32 {
802     x * x
803 }
804 fn main() {
805     let local = 51;
806     let y = square$0(local);
807 }
808 "#,
809             r#"
810 fn square(x: u32) -> u32 {
811     x * x
812 }
813 fn main() {
814     let local = 51;
815     let y = local * local;
816 }
817 "#,
818         );
819     }
820 
821     #[test]
method_in_impl()822     fn method_in_impl() {
823         check_assist(
824             inline_call,
825             r#"
826 struct Foo;
827 impl Foo {
828     fn foo(&self) {
829         self;
830         self;
831     }
832     fn bar(&self) {
833         self.foo$0();
834     }
835 }
836 "#,
837             r#"
838 struct Foo;
839 impl Foo {
840     fn foo(&self) {
841         self;
842         self;
843     }
844     fn bar(&self) {
845         {
846             let ref this = self;
847             this;
848             this;
849         };
850     }
851 }
852 "#,
853         );
854     }
855 
856     #[test]
wraps_closure_in_paren()857     fn wraps_closure_in_paren() {
858         cov_mark::check!(inline_call_inline_closure);
859         check_assist(
860             inline_call,
861             r#"
862 fn foo(x: fn()) {
863     x();
864 }
865 
866 fn main() {
867     foo$0(|| {})
868 }
869 "#,
870             r#"
871 fn foo(x: fn()) {
872     x();
873 }
874 
875 fn main() {
876     {
877         (|| {})();
878     }
879 }
880 "#,
881         );
882         check_assist(
883             inline_call,
884             r#"
885 fn foo(x: fn()) {
886     x();
887 }
888 
889 fn main() {
890     foo$0(main)
891 }
892 "#,
893             r#"
894 fn foo(x: fn()) {
895     x();
896 }
897 
898 fn main() {
899     {
900         main();
901     }
902 }
903 "#,
904         );
905     }
906 
907     #[test]
inline_single_literal_expr()908     fn inline_single_literal_expr() {
909         cov_mark::check!(inline_call_inline_literal);
910         check_assist(
911             inline_call,
912             r#"
913 fn foo(x: u32) -> u32{
914     x
915 }
916 
917 fn main() {
918     foo$0(222);
919 }
920 "#,
921             r#"
922 fn foo(x: u32) -> u32{
923     x
924 }
925 
926 fn main() {
927     222;
928 }
929 "#,
930         );
931     }
932 
933     #[test]
inline_emits_type_for_coercion()934     fn inline_emits_type_for_coercion() {
935         check_assist(
936             inline_call,
937             r#"
938 fn foo(x: *const u32) -> u32 {
939     x as u32
940 }
941 
942 fn main() {
943     foo$0(&222);
944 }
945 "#,
946             r#"
947 fn foo(x: *const u32) -> u32 {
948     x as u32
949 }
950 
951 fn main() {
952     {
953         let x: *const u32 = &222;
954         x as u32
955     };
956 }
957 "#,
958         );
959     }
960 
961     #[test]
inline_substitutes_generics()962     fn inline_substitutes_generics() {
963         check_assist(
964             inline_call,
965             r#"
966 fn foo<T, const N: usize>() {
967     bar::<T, N>()
968 }
969 
970 fn bar<U, const M: usize>() {}
971 
972 fn main() {
973     foo$0::<usize, {0}>();
974 }
975 "#,
976             r#"
977 fn foo<T, const N: usize>() {
978     bar::<T, N>()
979 }
980 
981 fn bar<U, const M: usize>() {}
982 
983 fn main() {
984     bar::<usize, {0}>();
985 }
986 "#,
987         );
988     }
989 
990     #[test]
inline_callers()991     fn inline_callers() {
992         check_assist(
993             inline_into_callers,
994             r#"
995 fn do_the_math$0(b: u32) -> u32 {
996     let foo = 10;
997     foo * b + foo
998 }
999 fn foo() {
1000     do_the_math(0);
1001     let bar = 10;
1002     do_the_math(bar);
1003 }
1004 "#,
1005             r#"
1006 
1007 fn foo() {
1008     {
1009         let foo = 10;
1010         foo * 0 + foo
1011     };
1012     let bar = 10;
1013     {
1014         let foo = 10;
1015         foo * bar + foo
1016     };
1017 }
1018 "#,
1019         );
1020     }
1021 
1022     #[test]
inline_callers_across_files()1023     fn inline_callers_across_files() {
1024         check_assist(
1025             inline_into_callers,
1026             r#"
1027 //- /lib.rs
1028 mod foo;
1029 fn do_the_math$0(b: u32) -> u32 {
1030     let foo = 10;
1031     foo * b + foo
1032 }
1033 //- /foo.rs
1034 use super::do_the_math;
1035 fn foo() {
1036     do_the_math(0);
1037     let bar = 10;
1038     do_the_math(bar);
1039 }
1040 "#,
1041             r#"
1042 //- /lib.rs
1043 mod foo;
1044 
1045 //- /foo.rs
1046 fn foo() {
1047     {
1048         let foo = 10;
1049         foo * 0 + foo
1050     };
1051     let bar = 10;
1052     {
1053         let foo = 10;
1054         foo * bar + foo
1055     };
1056 }
1057 "#,
1058         );
1059     }
1060 
1061     #[test]
inline_callers_across_files_with_def_file()1062     fn inline_callers_across_files_with_def_file() {
1063         check_assist(
1064             inline_into_callers,
1065             r#"
1066 //- /lib.rs
1067 mod foo;
1068 fn do_the_math$0(b: u32) -> u32 {
1069     let foo = 10;
1070     foo * b + foo
1071 }
1072 fn bar(a: u32, b: u32) -> u32 {
1073     do_the_math(0);
1074 }
1075 //- /foo.rs
1076 use super::do_the_math;
1077 fn foo() {
1078     do_the_math(0);
1079 }
1080 "#,
1081             r#"
1082 //- /lib.rs
1083 mod foo;
1084 
1085 fn bar(a: u32, b: u32) -> u32 {
1086     {
1087         let foo = 10;
1088         foo * 0 + foo
1089     };
1090 }
1091 //- /foo.rs
1092 fn foo() {
1093     {
1094         let foo = 10;
1095         foo * 0 + foo
1096     };
1097 }
1098 "#,
1099         );
1100     }
1101 
1102     #[test]
inline_callers_recursive()1103     fn inline_callers_recursive() {
1104         cov_mark::check!(inline_into_callers_recursive);
1105         check_assist_not_applicable(
1106             inline_into_callers,
1107             r#"
1108 fn foo$0() {
1109     foo();
1110 }
1111 "#,
1112         );
1113     }
1114 
1115     #[test]
inline_call_recursive()1116     fn inline_call_recursive() {
1117         cov_mark::check!(inline_call_recursive);
1118         check_assist_not_applicable(
1119             inline_call,
1120             r#"
1121 fn foo() {
1122     foo$0();
1123 }
1124 "#,
1125         );
1126     }
1127 
1128     #[test]
inline_call_field_shorthand()1129     fn inline_call_field_shorthand() {
1130         cov_mark::check!(inline_call_inline_direct_field);
1131         check_assist(
1132             inline_call,
1133             r#"
1134 struct Foo {
1135     field: u32,
1136     field1: u32,
1137     field2: u32,
1138     field3: u32,
1139 }
1140 fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1141     Foo {
1142         field,
1143         field1,
1144         field2: val2,
1145         field3: val3,
1146     }
1147 }
1148 fn main() {
1149     let bar = 0;
1150     let baz = 0;
1151     foo$0(bar, 0, baz, 0);
1152 }
1153 "#,
1154             r#"
1155 struct Foo {
1156     field: u32,
1157     field1: u32,
1158     field2: u32,
1159     field3: u32,
1160 }
1161 fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1162     Foo {
1163         field,
1164         field1,
1165         field2: val2,
1166         field3: val3,
1167     }
1168 }
1169 fn main() {
1170     let bar = 0;
1171     let baz = 0;
1172     Foo {
1173             field: bar,
1174             field1: 0,
1175             field2: baz,
1176             field3: 0,
1177         };
1178 }
1179 "#,
1180         );
1181     }
1182 
1183     #[test]
inline_callers_wrapped_in_parentheses()1184     fn inline_callers_wrapped_in_parentheses() {
1185         check_assist(
1186             inline_into_callers,
1187             r#"
1188 fn foo$0() -> u32 {
1189     let x = 0;
1190     x
1191 }
1192 fn bar() -> u32 {
1193     foo() + foo()
1194 }
1195 "#,
1196             r#"
1197 
1198 fn bar() -> u32 {
1199     ({
1200         let x = 0;
1201         x
1202     }) + {
1203         let x = 0;
1204         x
1205     }
1206 }
1207 "#,
1208         )
1209     }
1210 
1211     #[test]
inline_call_wrapped_in_parentheses()1212     fn inline_call_wrapped_in_parentheses() {
1213         check_assist(
1214             inline_call,
1215             r#"
1216 fn foo() -> u32 {
1217     let x = 0;
1218     x
1219 }
1220 fn bar() -> u32 {
1221     foo$0() + foo()
1222 }
1223 "#,
1224             r#"
1225 fn foo() -> u32 {
1226     let x = 0;
1227     x
1228 }
1229 fn bar() -> u32 {
1230     ({
1231         let x = 0;
1232         x
1233     }) + foo()
1234 }
1235 "#,
1236         )
1237     }
1238 
1239     #[test]
inline_call_defined_in_macro()1240     fn inline_call_defined_in_macro() {
1241         cov_mark::check!(inline_call_defined_in_macro);
1242         check_assist(
1243             inline_call,
1244             r#"
1245 macro_rules! define_foo {
1246     () => { fn foo() -> u32 {
1247         let x = 0;
1248         x
1249     } };
1250 }
1251 define_foo!();
1252 fn bar() -> u32 {
1253     foo$0()
1254 }
1255 "#,
1256             r#"
1257 macro_rules! define_foo {
1258     () => { fn foo() -> u32 {
1259         let x = 0;
1260         x
1261     } };
1262 }
1263 define_foo!();
1264 fn bar() -> u32 {
1265     {
1266       let x = 0;
1267       x
1268     }
1269 }
1270 "#,
1271         )
1272     }
1273 
1274     #[test]
inline_call_with_self_type()1275     fn inline_call_with_self_type() {
1276         check_assist(
1277             inline_call,
1278             r#"
1279 struct A(u32);
1280 impl A {
1281     fn f() -> Self { Self(114514) }
1282 }
1283 fn main() {
1284     A::f$0();
1285 }
1286 "#,
1287             r#"
1288 struct A(u32);
1289 impl A {
1290     fn f() -> Self { Self(114514) }
1291 }
1292 fn main() {
1293     A(114514);
1294 }
1295 "#,
1296         )
1297     }
1298 
1299     #[test]
inline_call_with_self_type_but_within_same_impl()1300     fn inline_call_with_self_type_but_within_same_impl() {
1301         check_assist(
1302             inline_call,
1303             r#"
1304 struct A(u32);
1305 impl A {
1306     fn f() -> Self { Self(1919810) }
1307     fn main() {
1308         Self::f$0();
1309     }
1310 }
1311 "#,
1312             r#"
1313 struct A(u32);
1314 impl A {
1315     fn f() -> Self { Self(1919810) }
1316     fn main() {
1317         Self(1919810);
1318     }
1319 }
1320 "#,
1321         )
1322     }
1323 
1324     #[test]
local_variable_shadowing_callers_argument()1325     fn local_variable_shadowing_callers_argument() {
1326         check_assist(
1327             inline_call,
1328             r#"
1329 fn foo(bar: u32, baz: u32) -> u32 {
1330     let a = 1;
1331     bar * baz * a * 6
1332 }
1333 fn main() {
1334     let a = 7;
1335     let b = 1;
1336     let res = foo$0(a, b);
1337 }
1338 "#,
1339             r#"
1340 fn foo(bar: u32, baz: u32) -> u32 {
1341     let a = 1;
1342     bar * baz * a * 6
1343 }
1344 fn main() {
1345     let a = 7;
1346     let b = 1;
1347     let res = {
1348         let bar = a;
1349         let a = 1;
1350         bar * b * a * 6
1351     };
1352 }
1353 "#,
1354         );
1355     }
1356 }
1357