Skip to main content

ide_assists/handlers/
inline_call.rs

1use std::collections::BTreeSet;
2
3use either::Either;
4use hir::{
5    FileRange, PathResolution, Semantics, TypeInfo,
6    db::{ExpandDatabase, HirDatabase},
7    sym,
8};
9use ide_db::{
10    EditionedFileId, FxHashMap, RootDatabase,
11    base_db::Crate,
12    defs::Definition,
13    imports::insert_use::remove_use_tree_if_simple,
14    path_transform::PathTransform,
15    search::{FileReference, FileReferenceNode, SearchScope},
16    syntax_helpers::{node_ext::expr_as_name_ref, prettify_macro_expansion},
17};
18use itertools::{Itertools, izip};
19use syntax::{
20    AstNode, NodeOrToken, SyntaxKind, TextRange,
21    ast::{
22        self, HasArgList, HasGenericArgs, Pat, PathExpr,
23        edit::{AstNodeEdit, IndentLevel},
24        syntax_factory::SyntaxFactory,
25    },
26    syntax_editor::SyntaxEditor,
27};
28
29use crate::{
30    AssistId,
31    assist_context::{AssistContext, Assists},
32};
33
34// Assist: inline_into_callers
35//
36// Inline a function or method body into all of its callers where possible, creating a `let` statement per parameter
37// unless the parameter can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
38// or if the parameter is only accessed inside the function body once.
39// If all calls can be inlined the function will be removed.
40//
41// ```
42// fn print(_: &str) {}
43// fn foo$0(word: &str) {
44//     if !word.is_empty() {
45//         print(word);
46//     }
47// }
48// fn bar() {
49//     foo("안녕하세요");
50//     foo("여러분");
51// }
52// ```
53// ->
54// ```
55// fn print(_: &str) {}
56//
57// fn bar() {
58//     {
59//         let word: &str = "안녕하세요";
60//         if !word.is_empty() {
61//             print(word);
62//         }
63//     };
64//     {
65//         let word: &str = "여러분";
66//         if !word.is_empty() {
67//             print(word);
68//         }
69//     };
70// }
71// ```
72pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
73    let def_file = ctx.file_id();
74    let vfs_def_file = ctx.vfs_file_id();
75    let name = ctx.find_node_at_offset::<ast::Name>()?;
76    let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
77    let func_body = ast_func.body()?;
78    let param_list = ast_func.param_list()?;
79
80    let function = ctx.sema.to_def(&ast_func)?;
81
82    let def_file_editor = SyntaxEditor::new(ast_func.syntax().ancestors().last().unwrap()).0;
83    let params = get_fn_params(ctx.sema.db, function, &param_list, def_file_editor.make())?;
84
85    let mut file_editors = FxHashMap::default();
86    file_editors.insert(vfs_def_file, def_file_editor);
87
88    let usages = Definition::Function(function).usages(&ctx.sema);
89    if !usages.at_least_one() {
90        return None;
91    }
92
93    let is_recursive_fn = usages
94        .clone()
95        .in_scope(&SearchScope::file_range(FileRange {
96            file_id: def_file,
97            range: func_body.syntax().text_range(),
98        }))
99        .at_least_one();
100    if is_recursive_fn {
101        cov_mark::hit!(inline_into_callers_recursive);
102        return None;
103    }
104
105    acc.add(
106        AssistId::refactor_inline("inline_into_callers"),
107        "Inline into all callers",
108        name.syntax().text_range(),
109        |builder| {
110            let mut usages = usages.all();
111            let current_file_usage = usages.references.remove(&def_file);
112
113            let mut remove_def = true;
114            let mut inline_refs_for_file = |file_id: EditionedFileId, refs: Vec<FileReference>| {
115                let file_id = file_id.file_id(ctx.db());
116                builder.edit_file(file_id);
117                let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate(ctx.db()));
118                let count = refs.len();
119                let (name_refs, use_trees) = split_refs_and_uses(refs, Some);
120                let call_infos: Vec<_> = name_refs
121                    .into_iter()
122                    .filter_map(|it| CallInfo::from_name_ref(it, call_krate?.into()))
123                    // FIXME: do not handle callsites in macros' parameters, because
124                    // directly inlining into macros may cause errors.
125                    .filter(|call_info| !ctx.sema.hir_file_for(call_info.node.syntax()).is_macro())
126                    .collect();
127
128                // Skip calls nested inside other calls being inlined to avoid overlapping
129                // edits. Nested calls are implicitly replaced when the outer call is inlined.
130                let all_ranges: Vec<TextRange> =
131                    call_infos.iter().map(|ci| ci.node.syntax().text_range()).collect();
132                let (call_infos, nested_infos): (Vec<_>, Vec<_>) =
133                    call_infos.into_iter().partition(|ci| {
134                        let r = ci.node.syntax().text_range();
135                        !all_ranges.iter().any(|&other| other != r && other.contains_range(r))
136                    });
137                let nested_count = nested_infos.len();
138
139                let anchor = call_infos
140                    .first()
141                    .map(|ci| ci.node.syntax().clone())
142                    .or_else(|| use_trees.first().map(|ut| ut.syntax().clone()));
143                if let Some(anchor) = anchor {
144                    let editor =
145                        file_editors.entry(file_id).or_insert_with(|| builder.make_editor(&anchor));
146                    let replaced = call_infos
147                        .into_iter()
148                        .map(|call_info| {
149                            let replacement = inline(
150                                &ctx.sema, def_file, function, &func_body, &params, &call_info,
151                                editor,
152                            );
153                            editor.replace(call_info.node.syntax(), replacement.syntax());
154                        })
155                        .count();
156                    if replaced + nested_count + use_trees.len() == count {
157                        // we replaced all usages in this file, so we can remove the imports
158                        for use_tree in &use_trees {
159                            remove_use_tree_if_simple(use_tree, editor);
160                        }
161                    } else {
162                        remove_def = false;
163                    }
164                } else if use_trees.len() != count {
165                    remove_def = false;
166                }
167            };
168            for (file_id, refs) in usages.into_iter() {
169                inline_refs_for_file(file_id, refs);
170            }
171            match current_file_usage {
172                Some(refs) => inline_refs_for_file(def_file, refs),
173                None => builder.edit_file(vfs_def_file),
174            }
175            if remove_def {
176                file_editors
177                    .entry(vfs_def_file)
178                    .or_insert_with(|| builder.make_editor(ast_func.syntax()))
179                    .delete(ast_func.syntax());
180            }
181            for (file_id, editor) in file_editors {
182                builder.add_file_edits(file_id, editor);
183            }
184        },
185    )
186}
187
188pub(super) fn split_refs_and_uses<T: ast::AstNode>(
189    iter: impl IntoIterator<Item = FileReference>,
190    mut map_ref: impl FnMut(ast::NameRef) -> Option<T>,
191) -> (Vec<T>, Vec<ast::UseTree>) {
192    iter.into_iter()
193        .filter_map(|file_ref| match file_ref.name {
194            FileReferenceNode::NameRef(name_ref) => Some(name_ref),
195            _ => None,
196        })
197        .filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
198            Some(use_tree) => Some(Either::Right(use_tree)),
199            None => map_ref(name_ref).map(Either::Left),
200        })
201        .partition_map(|either| either)
202}
203
204// Assist: inline_call
205//
206// Inlines a function or method body creating a `let` statement per parameter unless the parameter
207// can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
208// or if the parameter is only accessed inside the function body once.
209//
210// ```
211// # //- minicore: option
212// fn foo(name: Option<&str>) {
213//     let name = name.unwrap$0();
214// }
215// ```
216// ->
217// ```
218// fn foo(name: Option<&str>) {
219//     let name = match name {
220//             Some(val) => val,
221//             None => panic!("called `Option::unwrap()` on a `None` value"),
222//         };
223// }
224// ```
225pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
226    let name_ref: ast::NameRef = ctx.find_node_at_offset()?;
227    let call_info = CallInfo::from_name_ref(
228        name_ref.clone(),
229        ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into(),
230    )?;
231    let (function, label) = match &call_info.node {
232        ast::CallableExpr::Call(call) => {
233            let path = match call.expr()? {
234                ast::Expr::PathExpr(path) => path.path(),
235                _ => None,
236            }?;
237            let function = match ctx.sema.resolve_path(&path)? {
238                PathResolution::Def(hir::ModuleDef::Function(f)) => f,
239                _ => return None,
240            };
241            (function, format!("Inline `{path}`"))
242        }
243        ast::CallableExpr::MethodCall(call) => {
244            (ctx.sema.resolve_method_call(call)?, format!("Inline `{name_ref}`"))
245        }
246    };
247
248    let fn_source = ctx.sema.source(function)?;
249    let fn_body = fn_source.value.body()?;
250    let param_list = fn_source.value.param_list()?;
251
252    let FileRange { file_id, range } = fn_source.syntax().original_file_range_rooted(ctx.sema.db);
253    if file_id == ctx.file_id() && range.contains(ctx.offset()) {
254        cov_mark::hit!(inline_call_recursive);
255        return None;
256    }
257    let syntax = call_info.node.syntax().clone();
258    let editor = SyntaxEditor::new(syntax.ancestors().last().unwrap()).0;
259    let params = get_fn_params(ctx.sema.db, function, &param_list, editor.make())?;
260
261    if call_info.arguments.len() != params.len() {
262        // Can't inline the function because they've passed the wrong number of
263        // arguments to this function
264        cov_mark::hit!(inline_call_incorrect_number_of_arguments);
265        return None;
266    }
267
268    acc.add(AssistId::refactor_inline("inline_call"), label, syntax.text_range(), |builder| {
269        let replacement =
270            inline(&ctx.sema, file_id, function, &fn_body, &params, &call_info, &editor);
271        editor.replace(call_info.node.syntax(), replacement.syntax());
272        builder.add_file_edits(ctx.vfs_file_id(), editor);
273    })
274}
275
276struct CallInfo {
277    node: ast::CallableExpr,
278    arguments: Vec<ast::Expr>,
279    generic_arg_list: Option<ast::GenericArgList>,
280    krate: Crate,
281}
282
283impl CallInfo {
284    fn from_name_ref(name_ref: ast::NameRef, krate: Crate) -> Option<CallInfo> {
285        let parent = name_ref.syntax().parent()?;
286        if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) {
287            let receiver = call.receiver()?;
288            let mut arguments = vec![receiver];
289            arguments.extend(call.arg_list()?.args());
290            Some(CallInfo {
291                generic_arg_list: call.generic_arg_list(),
292                node: ast::CallableExpr::MethodCall(call),
293                arguments,
294                krate,
295            })
296        } else if let Some(segment) = ast::PathSegment::cast(parent) {
297            let path = segment.syntax().parent().and_then(ast::Path::cast)?;
298            let path = path.syntax().parent().and_then(ast::PathExpr::cast)?;
299            let call = path.syntax().parent().and_then(ast::CallExpr::cast)?;
300
301            Some(CallInfo {
302                arguments: call.arg_list()?.args().collect(),
303                node: ast::CallableExpr::Call(call),
304                generic_arg_list: segment.generic_arg_list(),
305                krate,
306            })
307        } else {
308            None
309        }
310    }
311}
312
313fn get_fn_params<'db>(
314    db: &'db dyn HirDatabase,
315    function: hir::Function,
316    param_list: &ast::ParamList,
317    make: &SyntaxFactory,
318) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param<'db>)>> {
319    let mut assoc_fn_params = function.assoc_fn_params(db).into_iter();
320
321    let mut params = Vec::new();
322    if let Some(self_param) = param_list.self_param() {
323        // Keep `ref` and `mut` and transform them into `&` and `mut` later
324        params.push((
325            make.ident_pat(
326                self_param.amp_token().is_some(),
327                self_param.mut_token().is_some(),
328                make.name("this"),
329            )
330            .into(),
331            None,
332            assoc_fn_params.next()?,
333        ));
334    }
335    for param in param_list.params() {
336        params.push((param.pat()?, param.ty(), assoc_fn_params.next()?));
337    }
338
339    Some(params)
340}
341
342fn inline(
343    sema: &Semantics<'_, RootDatabase>,
344    function_def_file_id: EditionedFileId,
345    function: hir::Function,
346    fn_body: &ast::BlockExpr,
347    params: &[(ast::Pat, Option<ast::Type>, hir::Param<'_>)],
348    CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo,
349    file_editor: &SyntaxEditor,
350) -> ast::Expr {
351    let make = file_editor.make();
352    let file_id = sema.hir_file_for(fn_body.syntax());
353    let body_to_clone = if let Some(macro_file) = file_id.macro_file() {
354        cov_mark::hit!(inline_call_defined_in_macro);
355        let span_map = sema.db.expansion_span_map(macro_file);
356        let body_prettified =
357            prettify_macro_expansion(sema.db, fn_body.syntax().clone(), span_map, *krate);
358        if let Some(body) = ast::BlockExpr::cast(body_prettified) { body } else { fn_body.clone() }
359    } else {
360        fn_body.clone()
361    };
362
363    // Capture before `with_ast_node` re-roots and loses the source-relative position.
364    let mut original_body_indent = IndentLevel::from_node(body_to_clone.syntax());
365    let body_offset = body_to_clone.syntax().text_range().start();
366    let (editor, body) = SyntaxEditor::with_ast_node(&body_to_clone);
367
368    let usages_for_locals = |local| {
369        Definition::Local(local)
370            .usages(sema)
371            .all()
372            .references
373            .remove(&function_def_file_id)
374            .unwrap_or_default()
375            .into_iter()
376    };
377    let param_use_nodes: Vec<Vec<_>> = params
378        .iter()
379        .map(|(pat, _, param)| {
380            if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {
381                return Vec::new();
382            }
383            // FIXME: we need to fetch all locals declared in the parameter here
384            // not only the local if it is a simple binding
385            match param.as_local(sema.db) {
386                Some(l) => usages_for_locals(l)
387                    .map(|FileReference { name, range, .. }| match name {
388                        FileReferenceNode::NameRef(_) => body
389                            .syntax()
390                            .covering_element(range - body_offset)
391                            .ancestors()
392                            .nth(3)
393                            .and_then(ast::PathExpr::cast),
394                        _ => None,
395                    })
396                    .collect::<Option<Vec<_>>>()
397                    .unwrap_or_default(),
398                None => Vec::new(),
399            }
400        })
401        .collect();
402
403    let has_self_param = function.self_param(sema.db).is_some();
404
405    // Collect all self token usages upfront (needed when a let binding is emitted).
406    // When self can be directly inlined, the parameter loop handles those PathExprs;
407    // when a let stmt is needed, we rename all self tokens to `this` here.
408    let self_token_usages: Vec<_> = if has_self_param {
409        params[0]
410            .2
411            .as_local(sema.db)
412            .map(|self_local| {
413                usages_for_locals(self_local)
414                    .filter_map(|FileReference { name, range, .. }| match name {
415                        FileReferenceNode::NameRef(_) => {
416                            Some(body.syntax().covering_element(range - body_offset))
417                        }
418                        _ => None,
419                    })
420                    .collect()
421            })
422            .unwrap_or_default()
423    } else {
424        Vec::new()
425    };
426
427    // Replace `Self` type keywords with the actual impl type
428    if let Some(imp) =
429        sema.ancestors_with_macros(fn_body.syntax().clone()).find_map(ast::Impl::cast)
430        && !node.syntax().ancestors().any(|anc| &anc == imp.syntax())
431        && let Some(t) = imp.self_ty()
432    {
433        let self_tokens: Vec<_> = body
434            .syntax()
435            .descendants_with_tokens()
436            .filter_map(NodeOrToken::into_token)
437            .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
438            .collect();
439        for self_tok in self_tokens {
440            let replace_with = if !is_in_type_path(&self_tok)
441                && let Some(generic_arg_list) = t.generic_arg_list()
442            {
443                // Strip the outer generic arg list and reparse, since turbofish-less
444                // generics aren't valid in expression position. The outermost
445                // `GenericArgList` text is unique within `t`'s text (any inner generics
446                // are nested inside it), so `replacen(.., 1)` is safe.
447                let stripped = t.syntax().text().to_string().replacen(
448                    &generic_arg_list.syntax().text().to_string(),
449                    "",
450                    1,
451                );
452                editor.make().ty(&stripped).syntax().clone()
453            } else {
454                t.syntax().clone()
455            };
456            editor.replace(self_tok, replace_with);
457        }
458    }
459
460    let mut func_let_vars: BTreeSet<String> = BTreeSet::new();
461
462    // grab all of the local variable declarations in the function
463    for stmt in fn_body.statements() {
464        if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) {
465            for has_token in let_stmt.syntax().children_with_tokens() {
466                if let Some(node) = has_token.as_node()
467                    && let Some(ident_pat) = ast::IdentPat::cast(node.to_owned())
468                {
469                    func_let_vars.insert(ident_pat.syntax().text().to_string());
470                }
471            }
472        }
473    }
474
475    let mut let_stmts: Vec<ast::Stmt> = Vec::new();
476
477    let this_token = editor
478        .make()
479        .name_ref("this")
480        .syntax()
481        .first_token()
482        .expect("NameRef should have had a token.");
483    let rewrite_self_to_this = |editor: &SyntaxEditor| {
484        for usage in &self_token_usages {
485            editor.replace(usage.clone(), this_token.clone());
486        }
487    };
488
489    // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
490    for ((pat, param_ty, param), usages, expr) in izip!(params, param_use_nodes, arguments) {
491        // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
492        let usages: &[ast::PathExpr] = &usages;
493        let expr: &ast::Expr = expr;
494
495        let mut insert_let_stmt = || {
496            let param_ty = param_ty.clone().map(|param_ty| {
497                let file_id = sema.hir_file_for(param_ty.syntax());
498                if let Some(macro_file) = file_id.macro_file() {
499                    let span_map = sema.db.expansion_span_map(macro_file);
500                    let param_ty_prettified = prettify_macro_expansion(
501                        sema.db,
502                        param_ty.syntax().clone(),
503                        span_map,
504                        *krate,
505                    );
506                    ast::Type::cast(param_ty_prettified).unwrap_or(param_ty)
507                } else {
508                    param_ty
509                }
510            });
511
512            let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty);
513
514            let is_self = param.name(sema.db).is_some_and(|name| name == sym::self_);
515
516            if is_self {
517                let mut this_pat = make.ident_pat(false, false, make.name("this"));
518                let mut expr = expr.clone();
519                if let Pat::IdentPat(pat) = pat {
520                    match (pat.ref_token(), pat.mut_token()) {
521                        // self => let this = obj
522                        (None, None) => {}
523                        // mut self => let mut this = obj
524                        (None, Some(_)) => {
525                            this_pat = make.ident_pat(false, true, make.name("this"));
526                        }
527                        // &self => let this = &obj
528                        (Some(_), None) => {
529                            expr = make.expr_ref(expr, false);
530                        }
531                        // let foo = &mut X; &mut self => let this = &mut obj
532                        // let mut foo = X;  &mut self => let this = &mut *obj (reborrow)
533                        (Some(_), Some(_)) => {
534                            let should_reborrow = sema
535                                .type_of_expr(&expr)
536                                .map(|ty| ty.original.is_mutable_reference());
537                            expr = if let Some(true) = should_reborrow {
538                                make.expr_reborrow(expr)
539                            } else {
540                                make.expr_ref(expr, true)
541                            };
542                        }
543                    }
544                };
545                let_stmts.push(make.let_stmt(this_pat.into(), ty, Some(expr)).into())
546            } else {
547                let_stmts.push(make.let_stmt(pat.clone(), ty, Some(expr.clone())).into());
548            }
549        };
550
551        let is_self_param =
552            has_self_param && param.name(sema.db).is_some_and(|name| name == sym::self_);
553
554        // check if there is a local var in the function that conflicts with parameter
555        // if it does then emit a let statement and continue
556        if func_let_vars.contains(&expr.syntax().text().to_string()) {
557            if is_self_param {
558                rewrite_self_to_this(&editor);
559            }
560            insert_let_stmt();
561            continue;
562        }
563
564        let inline_direct = |editor: &SyntaxEditor, usage: &PathExpr, replacement: &ast::Expr| {
565            if let Some(field) = path_expr_as_record_field(usage) {
566                cov_mark::hit!(inline_call_inline_direct_field);
567                field.replace_expr(editor, replacement.clone());
568            } else {
569                editor.replace(usage.syntax(), replacement.syntax());
570            }
571        };
572
573        match usages {
574            // inline single use closure arguments
575            [usage]
576                if matches!(expr, ast::Expr::ClosureExpr(_))
577                    && usage.syntax().parent().and_then(ast::Expr::cast).is_some() =>
578            {
579                cov_mark::hit!(inline_call_inline_closure);
580                let expr = editor.make().expr_paren(expr.clone()).into();
581                inline_direct(&editor, usage, &expr);
582            }
583            // inline single use literals
584            [usage] if matches!(expr, ast::Expr::Literal(_)) => {
585                cov_mark::hit!(inline_call_inline_literal);
586                inline_direct(&editor, usage, expr);
587            }
588            // inline direct local arguments
589            [_, ..] if expr_as_name_ref(expr).is_some() => {
590                cov_mark::hit!(inline_call_inline_locals);
591                usages.iter().for_each(|usage| inline_direct(&editor, usage, expr));
592            }
593            // can't inline, emit a let statement
594            _ => {
595                if is_self_param {
596                    // Rename all `self` tokens to `this` so the let binding matches.
597                    rewrite_self_to_this(&editor);
598                }
599                insert_let_stmt();
600            }
601        }
602    }
603
604    // Apply all edits to get the transformed body
605    let edit = editor.finish();
606    let mut body = ast::BlockExpr::cast(edit.new_root().clone())
607        .expect("editor root should still be a BlockExpr");
608
609    // Apply generic substitution (needs immutable tree)
610    if let Some(generic_arg_list) = generic_arg_list.clone()
611        && let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
612        && let Some(new_body) = ast::BlockExpr::cast(
613            PathTransform::function_call(target, source, function, generic_arg_list)
614                .apply(body.syntax()),
615        )
616    {
617        body = new_body;
618    }
619
620    let is_async_fn = function.is_async(sema.db);
621    if is_async_fn {
622        cov_mark::hit!(inline_call_async_fn);
623        body = make.async_move_block_expr(body.statements(), body.tail_expr());
624
625        // Arguments should be evaluated outside the async block, and then moved into it.
626        if !let_stmts.is_empty() {
627            cov_mark::hit!(inline_call_async_fn_with_let_stmts);
628            body = body.indent(IndentLevel(1));
629            body = make.block_expr(let_stmts, Some(body.into()));
630        }
631    } else if !let_stmts.is_empty() {
632        // Prepend let statements to the body's existing statements
633        let stmts: Vec<ast::Stmt> = let_stmts.into_iter().chain(body.statements()).collect();
634        body = make.block_expr(stmts, body.tail_expr());
635        original_body_indent = IndentLevel(0);
636    }
637
638    let original_indentation = match node {
639        ast::CallableExpr::Call(it) => it.indent_level(),
640        ast::CallableExpr::MethodCall(it) => it.indent_level(),
641    };
642    body = body.dedent(original_body_indent).indent(original_indentation);
643
644    let no_stmts = body.statements().next().is_none();
645    match body.tail_expr() {
646        Some(expr) if matches!(expr, ast::Expr::ClosureExpr(_)) && no_stmts => {
647            make.expr_paren(expr).into()
648        }
649        Some(expr) if !is_async_fn && no_stmts => expr,
650        _ => match node
651            .syntax()
652            .parent()
653            .and_then(ast::BinExpr::cast)
654            .and_then(|bin_expr| bin_expr.lhs())
655        {
656            Some(lhs) if lhs.syntax() == node.syntax() => {
657                make.expr_paren(ast::Expr::BlockExpr(body)).into()
658            }
659            _ => ast::Expr::BlockExpr(body),
660        },
661    }
662}
663
664fn is_in_type_path(self_tok: &syntax::SyntaxToken) -> bool {
665    self_tok
666        .parent_ancestors()
667        .skip_while(|it| !ast::Path::can_cast(it.kind()))
668        .map_while(ast::Path::cast)
669        .last()
670        .and_then(|it| it.syntax().parent())
671        .and_then(ast::PathType::cast)
672        .is_some()
673}
674
675fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {
676    let path = usage.path()?;
677    let name_ref = path.as_single_name_ref()?;
678    ast::RecordExprField::for_name_ref(&name_ref)
679}
680
681#[cfg(test)]
682mod tests {
683    use crate::tests::{check_assist, check_assist_not_applicable};
684
685    use super::*;
686
687    #[test]
688    fn no_args_or_return_value_gets_inlined_without_block() {
689        check_assist(
690            inline_call,
691            r#"
692fn foo() { println!("Hello, World!"); }
693fn main() {
694    fo$0o();
695}
696"#,
697            r#"
698fn foo() { println!("Hello, World!"); }
699fn main() {
700    { println!("Hello, World!"); };
701}
702"#,
703        );
704    }
705
706    #[test]
707    fn not_applicable_when_incorrect_number_of_parameters_are_provided() {
708        cov_mark::check!(inline_call_incorrect_number_of_arguments);
709        check_assist_not_applicable(
710            inline_call,
711            r#"
712fn add(a: u32, b: u32) -> u32 { a + b }
713fn main() { let x = add$0(42); }
714"#,
715        );
716    }
717
718    #[test]
719    fn args_with_side_effects() {
720        check_assist(
721            inline_call,
722            r#"
723fn foo(name: String) {
724    println!("Hello, {}!", name);
725}
726fn main() {
727    foo$0(String::from("Michael"));
728}
729"#,
730            r#"
731fn foo(name: String) {
732    println!("Hello, {}!", name);
733}
734fn main() {
735    {
736        let name = String::from("Michael");
737        println!("Hello, {}!", name);
738    };
739}
740"#,
741        );
742    }
743
744    #[test]
745    fn function_with_multiple_statements() {
746        check_assist(
747            inline_call,
748            r#"
749fn foo(a: u32, b: u32) -> u32 {
750    let x = a + b;
751    let y = x - b;
752    x * y
753}
754
755fn main() {
756    let x = foo$0(1, 2);
757}
758"#,
759            r#"
760fn foo(a: u32, b: u32) -> u32 {
761    let x = a + b;
762    let y = x - b;
763    x * y
764}
765
766fn main() {
767    let x = {
768        let b = 2;
769        let x = 1 + b;
770        let y = x - b;
771        x * y
772    };
773}
774"#,
775        );
776    }
777
778    #[test]
779    fn function_with_self_param() {
780        check_assist(
781            inline_call,
782            r#"
783struct Foo(u32);
784
785impl Foo {
786    fn add(self, a: u32) -> Self {
787        Foo(self.0 + a)
788    }
789}
790
791fn main() {
792    let x = Foo::add$0(Foo(3), 2);
793}
794"#,
795            r#"
796struct Foo(u32);
797
798impl Foo {
799    fn add(self, a: u32) -> Self {
800        Foo(self.0 + a)
801    }
802}
803
804fn main() {
805    let x = {
806        let this = Foo(3);
807        Foo(this.0 + 2)
808    };
809}
810"#,
811        );
812    }
813
814    #[test]
815    fn method_by_val() {
816        check_assist(
817            inline_call,
818            r#"
819struct Foo(u32);
820
821impl Foo {
822    fn add(self, a: u32) -> Self {
823        Foo(self.0 + a)
824    }
825}
826
827fn main() {
828    let x = Foo(3).add$0(2);
829}
830"#,
831            r#"
832struct Foo(u32);
833
834impl Foo {
835    fn add(self, a: u32) -> Self {
836        Foo(self.0 + a)
837    }
838}
839
840fn main() {
841    let x = {
842        let this = Foo(3);
843        Foo(this.0 + 2)
844    };
845}
846"#,
847        );
848    }
849
850    #[test]
851    fn method_by_ref() {
852        check_assist(
853            inline_call,
854            r#"
855struct Foo(u32);
856
857impl Foo {
858    fn add(&self, a: u32) -> Self {
859        Foo(self.0 + a)
860    }
861}
862
863fn main() {
864    let x = Foo(3).add$0(2);
865}
866"#,
867            r#"
868struct Foo(u32);
869
870impl Foo {
871    fn add(&self, a: u32) -> Self {
872        Foo(self.0 + a)
873    }
874}
875
876fn main() {
877    let x = {
878        let this = &Foo(3);
879        Foo(this.0 + 2)
880    };
881}
882"#,
883        );
884    }
885
886    #[test]
887    fn generic_method_by_ref() {
888        check_assist(
889            inline_call,
890            r#"
891struct Foo(u32);
892
893impl Foo {
894    fn add<T>(&self, a: u32) -> Self {
895        Foo(self.0 + a)
896    }
897}
898
899fn main() {
900    let x = Foo(3).add$0::<usize>(2);
901}
902"#,
903            r#"
904struct Foo(u32);
905
906impl Foo {
907    fn add<T>(&self, a: u32) -> Self {
908        Foo(self.0 + a)
909    }
910}
911
912fn main() {
913    let x = {
914        let this = &Foo(3);
915        Foo(this.0 + 2)
916    };
917}
918"#,
919        );
920    }
921
922    #[test]
923    fn method_by_ref_mut() {
924        check_assist(
925            inline_call,
926            r#"
927struct Foo(u32);
928
929impl Foo {
930    fn clear(&mut self) {
931        self.0 = 0;
932    }
933}
934
935fn main() {
936    let mut foo = Foo(3);
937    foo.clear$0();
938}
939"#,
940            r#"
941struct Foo(u32);
942
943impl Foo {
944    fn clear(&mut self) {
945        self.0 = 0;
946    }
947}
948
949fn main() {
950    let mut foo = Foo(3);
951    {
952        let this = &mut foo;
953        this.0 = 0;
954    };
955}
956"#,
957        );
958    }
959
960    #[test]
961    fn function_multi_use_expr_in_param() {
962        check_assist(
963            inline_call,
964            r#"
965fn square(x: u32) -> u32 {
966    x * x
967}
968fn main() {
969    let x = 51;
970    let y = square$0(10 + x);
971}
972"#,
973            r#"
974fn square(x: u32) -> u32 {
975    x * x
976}
977fn main() {
978    let x = 51;
979    let y = {
980        let x = 10 + x;
981        x * x
982    };
983}
984"#,
985        );
986    }
987
988    #[test]
989    fn function_use_local_in_param() {
990        cov_mark::check!(inline_call_inline_locals);
991        check_assist(
992            inline_call,
993            r#"
994fn square(x: u32) -> u32 {
995    x * x
996}
997fn main() {
998    let local = 51;
999    let y = square$0(local);
1000}
1001"#,
1002            r#"
1003fn square(x: u32) -> u32 {
1004    x * x
1005}
1006fn main() {
1007    let local = 51;
1008    let y = local * local;
1009}
1010"#,
1011        );
1012    }
1013
1014    #[test]
1015    fn method_in_impl() {
1016        check_assist(
1017            inline_call,
1018            r#"
1019struct Foo;
1020impl Foo {
1021    fn foo(&self) {
1022        self;
1023        self;
1024    }
1025    fn bar(&self) {
1026        self.foo$0();
1027    }
1028}
1029"#,
1030            r#"
1031struct Foo;
1032impl Foo {
1033    fn foo(&self) {
1034        self;
1035        self;
1036    }
1037    fn bar(&self) {
1038        {
1039            let this = &self;
1040            this;
1041            this;
1042        };
1043    }
1044}
1045"#,
1046        );
1047    }
1048
1049    #[test]
1050    fn wraps_closure_in_paren() {
1051        cov_mark::check!(inline_call_inline_closure);
1052        check_assist(
1053            inline_call,
1054            r#"
1055fn foo(x: fn()) {
1056    x();
1057}
1058
1059fn main() {
1060    foo$0(|| {})
1061}
1062"#,
1063            r#"
1064fn foo(x: fn()) {
1065    x();
1066}
1067
1068fn main() {
1069    {
1070        (|| {})();
1071    }
1072}
1073"#,
1074        );
1075        check_assist(
1076            inline_call,
1077            r#"
1078fn foo(x: fn()) {
1079    x();
1080}
1081
1082fn main() {
1083    foo$0(main)
1084}
1085"#,
1086            r#"
1087fn foo(x: fn()) {
1088    x();
1089}
1090
1091fn main() {
1092    {
1093        main();
1094    }
1095}
1096"#,
1097        );
1098    }
1099
1100    #[test]
1101    fn inline_single_literal_expr() {
1102        cov_mark::check!(inline_call_inline_literal);
1103        check_assist(
1104            inline_call,
1105            r#"
1106fn foo(x: u32) -> u32{
1107    x
1108}
1109
1110fn main() {
1111    foo$0(222);
1112}
1113"#,
1114            r#"
1115fn foo(x: u32) -> u32{
1116    x
1117}
1118
1119fn main() {
1120    222;
1121}
1122"#,
1123        );
1124    }
1125
1126    #[test]
1127    fn inline_emits_type_for_coercion() {
1128        check_assist(
1129            inline_call,
1130            r#"
1131//- minicore: sized
1132fn foo(x: *const u32) -> u32 {
1133    x as u32
1134}
1135
1136fn main() {
1137    foo$0(&222);
1138}
1139"#,
1140            r#"
1141fn foo(x: *const u32) -> u32 {
1142    x as u32
1143}
1144
1145fn main() {
1146    {
1147        let x: *const u32 = &222;
1148        x as u32
1149    };
1150}
1151"#,
1152        );
1153    }
1154
1155    #[test]
1156    fn inline_substitutes_generics() {
1157        check_assist(
1158            inline_call,
1159            r#"
1160fn foo<T, const N: usize>() {
1161    bar::<T, N>()
1162}
1163
1164fn bar<U, const M: usize>() {}
1165
1166fn main() {
1167    foo$0::<usize, {0}>();
1168}
1169"#,
1170            r#"
1171fn foo<T, const N: usize>() {
1172    bar::<T, N>()
1173}
1174
1175fn bar<U, const M: usize>() {}
1176
1177fn main() {
1178    bar::<usize, {0}>();
1179}
1180"#,
1181        );
1182    }
1183
1184    #[test]
1185    fn inline_callers() {
1186        check_assist(
1187            inline_into_callers,
1188            r#"
1189fn do_the_math$0(b: u32) -> u32 {
1190    let foo = 10;
1191    foo * b + foo
1192}
1193fn foo() {
1194    do_the_math(0);
1195    let bar = 10;
1196    do_the_math(bar);
1197}
1198"#,
1199            r#"
1200
1201fn foo() {
1202    {
1203        let foo = 10;
1204        foo * 0 + foo
1205    };
1206    let bar = 10;
1207    {
1208        let foo = 10;
1209        foo * bar + foo
1210    };
1211}
1212"#,
1213        );
1214    }
1215
1216    #[test]
1217    fn inline_callers_across_files() {
1218        check_assist(
1219            inline_into_callers,
1220            r#"
1221//- /lib.rs
1222mod foo;
1223fn do_the_math$0(b: u32) -> u32 {
1224    let foo = 10;
1225    foo * b + foo
1226}
1227//- /foo.rs
1228use super::do_the_math;
1229fn foo() {
1230    do_the_math(0);
1231    let bar = 10;
1232    do_the_math(bar);
1233}
1234"#,
1235            r#"
1236//- /lib.rs
1237mod foo;
1238
1239//- /foo.rs
1240fn foo() {
1241    {
1242        let foo = 10;
1243        foo * 0 + foo
1244    };
1245    let bar = 10;
1246    {
1247        let foo = 10;
1248        foo * bar + foo
1249    };
1250}
1251"#,
1252        );
1253    }
1254
1255    #[test]
1256    fn inline_callers_across_files_with_def_file() {
1257        check_assist(
1258            inline_into_callers,
1259            r#"
1260//- /lib.rs
1261mod foo;
1262fn do_the_math$0(b: u32) -> u32 {
1263    let foo = 10;
1264    foo * b + foo
1265}
1266fn bar(a: u32, b: u32) -> u32 {
1267    do_the_math(0);
1268}
1269//- /foo.rs
1270use super::do_the_math;
1271fn foo() {
1272    do_the_math(0);
1273}
1274"#,
1275            r#"
1276//- /lib.rs
1277mod foo;
1278
1279fn bar(a: u32, b: u32) -> u32 {
1280    {
1281        let foo = 10;
1282        foo * 0 + foo
1283    };
1284}
1285//- /foo.rs
1286fn foo() {
1287    {
1288        let foo = 10;
1289        foo * 0 + foo
1290    };
1291}
1292"#,
1293        );
1294    }
1295
1296    #[test]
1297    fn inline_callers_recursive() {
1298        cov_mark::check!(inline_into_callers_recursive);
1299        check_assist_not_applicable(
1300            inline_into_callers,
1301            r#"
1302fn foo$0() {
1303    foo();
1304}
1305"#,
1306        );
1307    }
1308
1309    #[test]
1310    fn inline_call_recursive() {
1311        cov_mark::check!(inline_call_recursive);
1312        check_assist_not_applicable(
1313            inline_call,
1314            r#"
1315fn foo() {
1316    foo$0();
1317}
1318"#,
1319        );
1320    }
1321
1322    #[test]
1323    fn inline_call_field_shorthand() {
1324        cov_mark::check!(inline_call_inline_direct_field);
1325        check_assist(
1326            inline_call,
1327            r#"
1328struct Foo {
1329    field: u32,
1330    field1: u32,
1331    field2: u32,
1332    field3: u32,
1333}
1334fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1335    Foo {
1336        field,
1337        field1,
1338        field2: val2,
1339        field3: val3,
1340    }
1341}
1342fn main() {
1343    let bar = 0;
1344    let baz = 0;
1345    foo$0(bar, 0, baz, 0);
1346}
1347"#,
1348            r#"
1349struct Foo {
1350    field: u32,
1351    field1: u32,
1352    field2: u32,
1353    field3: u32,
1354}
1355fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1356    Foo {
1357        field,
1358        field1,
1359        field2: val2,
1360        field3: val3,
1361    }
1362}
1363fn main() {
1364    let bar = 0;
1365    let baz = 0;
1366    Foo {
1367            field: bar,
1368            field1: 0,
1369            field2: baz,
1370            field3: 0,
1371        };
1372}
1373"#,
1374        );
1375    }
1376
1377    #[test]
1378    fn inline_callers_wrapped_in_parentheses() {
1379        check_assist(
1380            inline_into_callers,
1381            r#"
1382fn foo$0() -> u32 {
1383    let x = 0;
1384    x
1385}
1386fn bar() -> u32 {
1387    foo() + foo()
1388}
1389"#,
1390            r#"
1391
1392fn bar() -> u32 {
1393    ({
1394        let x = 0;
1395        x
1396    }) + {
1397        let x = 0;
1398        x
1399    }
1400}
1401"#,
1402        )
1403    }
1404
1405    #[test]
1406    fn inline_call_wrapped_in_parentheses() {
1407        check_assist(
1408            inline_call,
1409            r#"
1410fn foo() -> u32 {
1411    let x = 0;
1412    x
1413}
1414fn bar() -> u32 {
1415    foo$0() + foo()
1416}
1417"#,
1418            r#"
1419fn foo() -> u32 {
1420    let x = 0;
1421    x
1422}
1423fn bar() -> u32 {
1424    ({
1425        let x = 0;
1426        x
1427    }) + foo()
1428}
1429"#,
1430        )
1431    }
1432
1433    #[test]
1434    fn inline_call_defined_in_macro() {
1435        cov_mark::check!(inline_call_defined_in_macro);
1436        check_assist(
1437            inline_call,
1438            r#"
1439macro_rules! define_foo {
1440    () => { fn foo() -> u32 {
1441        let x = 0;
1442        x
1443    } };
1444}
1445define_foo!();
1446fn bar() -> u32 {
1447    foo$0()
1448}
1449"#,
1450            r#"
1451macro_rules! define_foo {
1452    () => { fn foo() -> u32 {
1453        let x = 0;
1454        x
1455    } };
1456}
1457define_foo!();
1458fn bar() -> u32 {
1459    {
1460        let x = 0;
1461        x
1462    }
1463}
1464"#,
1465        )
1466    }
1467
1468    #[test]
1469    fn inline_call_with_self_type() {
1470        check_assist(
1471            inline_call,
1472            r#"
1473struct A(u32);
1474impl A {
1475    fn f() -> Self { Self(114514) }
1476}
1477fn main() {
1478    A::f$0();
1479}
1480"#,
1481            r#"
1482struct A(u32);
1483impl A {
1484    fn f() -> Self { Self(114514) }
1485}
1486fn main() {
1487    A(114514);
1488}
1489"#,
1490        )
1491    }
1492
1493    #[test]
1494    fn inline_call_with_self_type_but_within_same_impl() {
1495        check_assist(
1496            inline_call,
1497            r#"
1498struct A(u32);
1499impl A {
1500    fn f() -> Self { Self(1919810) }
1501    fn main() {
1502        Self::f$0();
1503    }
1504}
1505"#,
1506            r#"
1507struct A(u32);
1508impl A {
1509    fn f() -> Self { Self(1919810) }
1510    fn main() {
1511        Self(1919810);
1512    }
1513}
1514"#,
1515        )
1516    }
1517
1518    #[test]
1519    fn local_variable_shadowing_callers_argument() {
1520        check_assist(
1521            inline_call,
1522            r#"
1523fn foo(bar: u32, baz: u32) -> u32 {
1524    let a = 1;
1525    bar * baz * a * 6
1526}
1527fn main() {
1528    let a = 7;
1529    let b = 1;
1530    let res = foo$0(a, b);
1531}
1532"#,
1533            r#"
1534fn foo(bar: u32, baz: u32) -> u32 {
1535    let a = 1;
1536    bar * baz * a * 6
1537}
1538fn main() {
1539    let a = 7;
1540    let b = 1;
1541    let res = {
1542        let bar = a;
1543        let a = 1;
1544        bar * b * a * 6
1545    };
1546}
1547"#,
1548        );
1549    }
1550
1551    #[test]
1552    fn async_fn_single_expression() {
1553        cov_mark::check!(inline_call_async_fn);
1554        check_assist(
1555            inline_call,
1556            r#"
1557async fn bar(x: u32) -> u32 { x + 1 }
1558async fn foo(arg: u32) -> u32 {
1559    bar(arg).await * 2
1560}
1561fn spawn<T>(_: T) {}
1562fn main() {
1563    spawn(foo$0(42));
1564}
1565"#,
1566            r#"
1567async fn bar(x: u32) -> u32 { x + 1 }
1568async fn foo(arg: u32) -> u32 {
1569    bar(arg).await * 2
1570}
1571fn spawn<T>(_: T) {}
1572fn main() {
1573    spawn({
1574        let arg = 42;
1575        async move {
1576            bar(arg).await * 2
1577        }
1578    });
1579}
1580"#,
1581        );
1582    }
1583
1584    #[test]
1585    fn async_fn_multiple_statements() {
1586        cov_mark::check!(inline_call_async_fn);
1587        check_assist(
1588            inline_call,
1589            r#"
1590async fn bar(x: u32) -> u32 { x + 1 }
1591async fn foo(arg: u32) -> u32 {
1592    bar(arg).await;
1593    42
1594}
1595fn spawn<T>(_: T) {}
1596fn main() {
1597    spawn(foo$0(42));
1598}
1599"#,
1600            r#"
1601async fn bar(x: u32) -> u32 { x + 1 }
1602async fn foo(arg: u32) -> u32 {
1603    bar(arg).await;
1604    42
1605}
1606fn spawn<T>(_: T) {}
1607fn main() {
1608    spawn({
1609        let arg = 42;
1610        async move {
1611            bar(arg).await;
1612            42
1613        }
1614    });
1615}
1616"#,
1617        );
1618    }
1619
1620    #[test]
1621    fn async_fn_with_let_statements() {
1622        cov_mark::check!(inline_call_async_fn);
1623        cov_mark::check!(inline_call_async_fn_with_let_stmts);
1624        check_assist(
1625            inline_call,
1626            r#"
1627async fn bar(x: u32) -> u32 { x + 1 }
1628async fn foo(x: u32, y: u32, z: &u32) -> u32 {
1629    bar(x).await;
1630    y + y + *z
1631}
1632fn spawn<T>(_: T) {}
1633fn main() {
1634    let var = 42;
1635    spawn(foo$0(var, var + 1, &var));
1636}
1637"#,
1638            r#"
1639async fn bar(x: u32) -> u32 { x + 1 }
1640async fn foo(x: u32, y: u32, z: &u32) -> u32 {
1641    bar(x).await;
1642    y + y + *z
1643}
1644fn spawn<T>(_: T) {}
1645fn main() {
1646    let var = 42;
1647    spawn({
1648        let x = var;
1649        let y = var + 1;
1650        let z: &u32 = &var;
1651        async move {
1652            bar(x).await;
1653            y + y + *z
1654        }
1655    });
1656}
1657"#,
1658        );
1659    }
1660
1661    #[test]
1662    fn inline_call_closure_body() {
1663        check_assist(
1664            inline_call,
1665            r#"
1666fn f() -> impl Fn() -> i32 {
1667    || 2
1668}
1669
1670fn main() {
1671    let _ = $0f()();
1672}
1673"#,
1674            r#"
1675fn f() -> impl Fn() -> i32 {
1676    || 2
1677}
1678
1679fn main() {
1680    let _ = (|| 2)();
1681}
1682"#,
1683        );
1684    }
1685
1686    #[test]
1687    fn inline_call_with_multiple_self_types_eq() {
1688        check_assist(
1689            inline_call,
1690            r#"
1691#[derive(PartialEq, Eq)]
1692enum Enum {
1693    A,
1694    B,
1695}
1696
1697impl Enum {
1698    fn a_or_b_eq(&self) -> bool {
1699        self == &Self::A || self == &Self::B
1700    }
1701}
1702
1703fn a() -> bool {
1704    Enum::A.$0a_or_b_eq()
1705}
1706"#,
1707            r#"
1708#[derive(PartialEq, Eq)]
1709enum Enum {
1710    A,
1711    B,
1712}
1713
1714impl Enum {
1715    fn a_or_b_eq(&self) -> bool {
1716        self == &Self::A || self == &Self::B
1717    }
1718}
1719
1720fn a() -> bool {
1721    {
1722        let this = &Enum::A;
1723        this == &Enum::A || this == &Enum::B
1724    }
1725}
1726"#,
1727        )
1728    }
1729
1730    #[test]
1731    fn inline_call_with_self_type_in_macros() {
1732        check_assist(
1733            inline_call,
1734            r#"
1735trait Trait<T1> {
1736    fn f(a: T1) -> Self;
1737}
1738
1739macro_rules! impl_from {
1740    ($t: ty) => {
1741        impl Trait<$t> for $t {
1742            fn f(a: $t) -> Self {
1743                a as Self
1744            }
1745        }
1746    };
1747}
1748
1749struct A {}
1750
1751impl_from!(A);
1752
1753fn main() {
1754    let a: A = A{};
1755    let b = <A as Trait<A>>::$0f(a);
1756}
1757"#,
1758            r#"
1759trait Trait<T1> {
1760    fn f(a: T1) -> Self;
1761}
1762
1763macro_rules! impl_from {
1764    ($t: ty) => {
1765        impl Trait<$t> for $t {
1766            fn f(a: $t) -> Self {
1767                a as Self
1768            }
1769        }
1770    };
1771}
1772
1773struct A {}
1774
1775impl_from!(A);
1776
1777fn main() {
1778    let a: A = A{};
1779    let b = {
1780        let a = a;
1781        a as A
1782    };
1783}
1784"#,
1785        )
1786    }
1787
1788    #[test]
1789    fn inline_trait_method_call_with_lifetimes() {
1790        check_assist(
1791            inline_call,
1792            r#"
1793trait Trait {
1794    fn f() -> Self;
1795}
1796struct Foo<'a>(&'a ());
1797impl<'a> Trait for Foo<'a> {
1798    fn f() -> Self { Self(&()) }
1799}
1800impl Foo<'_> {
1801    fn new() -> Self {
1802        Self::$0f()
1803    }
1804}
1805"#,
1806            r#"
1807trait Trait {
1808    fn f() -> Self;
1809}
1810struct Foo<'a>(&'a ());
1811impl<'a> Trait for Foo<'a> {
1812    fn f() -> Self { Self(&()) }
1813}
1814impl Foo<'_> {
1815    fn new() -> Self {
1816        Foo(&())
1817    }
1818}
1819"#,
1820        )
1821    }
1822
1823    #[test]
1824    fn method_by_reborrow() {
1825        check_assist(
1826            inline_call,
1827            r#"
1828pub struct Foo(usize);
1829
1830impl Foo {
1831    fn add1(&mut self) {
1832        self.0 += 1;
1833    }
1834}
1835
1836pub fn main() {
1837    let f = &mut Foo(0);
1838    f.add1$0();
1839}
1840"#,
1841            r#"
1842pub struct Foo(usize);
1843
1844impl Foo {
1845    fn add1(&mut self) {
1846        self.0 += 1;
1847    }
1848}
1849
1850pub fn main() {
1851    let f = &mut Foo(0);
1852    {
1853        let this = &mut *f;
1854        this.0 += 1;
1855    };
1856}
1857"#,
1858        )
1859    }
1860
1861    #[test]
1862    fn method_by_mut() {
1863        check_assist(
1864            inline_call,
1865            r#"
1866pub struct Foo(usize);
1867
1868impl Foo {
1869    fn add1(mut self) {
1870        self.0 += 1;
1871    }
1872}
1873
1874pub fn main() {
1875    let mut f = Foo(0);
1876    f.add1$0();
1877}
1878"#,
1879            r#"
1880pub struct Foo(usize);
1881
1882impl Foo {
1883    fn add1(mut self) {
1884        self.0 += 1;
1885    }
1886}
1887
1888pub fn main() {
1889    let mut f = Foo(0);
1890    {
1891        let mut this = f;
1892        this.0 += 1;
1893    };
1894}
1895"#,
1896        )
1897    }
1898
1899    #[test]
1900    fn inline_call_with_reference_in_macros() {
1901        check_assist(
1902            inline_call,
1903            r#"
1904fn _write_u64(s: &mut u64, x: u64) {
1905    *s += x;
1906}
1907macro_rules! impl_write {
1908    ($(($ty:ident, $meth:ident),)*) => {$(
1909        fn _hash(inner_self_: &u64, state: &mut u64) {
1910            $meth(state, *inner_self_)
1911        }
1912    )*}
1913}
1914impl_write! { (u64, _write_u64), }
1915fn _hash2(self_: &u64, state: &mut u64) {
1916    $0_hash(&self_, state);
1917}
1918"#,
1919            r#"
1920fn _write_u64(s: &mut u64, x: u64) {
1921    *s += x;
1922}
1923macro_rules! impl_write {
1924    ($(($ty:ident, $meth:ident),)*) => {$(
1925        fn _hash(inner_self_: &u64, state: &mut u64) {
1926            $meth(state, *inner_self_)
1927        }
1928    )*}
1929}
1930impl_write! { (u64, _write_u64), }
1931fn _hash2(self_: &u64, state: &mut u64) {
1932    {
1933        let inner_self_: &u64 = &self_;
1934        let state: &mut u64 = state;
1935        _write_u64(state, *inner_self_)
1936    };
1937}
1938"#,
1939        )
1940    }
1941
1942    #[test]
1943    fn inline_callers_nested_calls() {
1944        check_assist(
1945            inline_into_callers,
1946            r#"
1947fn id$0(x: u32) -> u32 { x }
1948fn main() {
1949    let x = id(id(1));
1950}
1951"#,
1952            r#"
1953
1954fn main() {
1955    let x = {
1956        let x = id(1);
1957        x
1958    };
1959}
1960"#,
1961        );
1962    }
1963
1964    #[test]
1965    fn inline_into_callers_in_macros_not_applicable() {
1966        check_assist_not_applicable(
1967            inline_into_callers,
1968            r#"
1969fn foo() -> u32 {
1970    42
1971}
1972
1973macro_rules! bar {
1974    ($x:expr) => {
1975      $x
1976    };
1977}
1978
1979fn f() {
1980    bar!(foo$0());
1981}
1982"#,
1983        );
1984    }
1985}