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
34pub(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, ¶m_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 .filter(|call_info| !ctx.sema.hir_file_for(call_info.node.syntax()).is_macro())
126 .collect();
127
128 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, ¶ms, &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 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
204pub(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, ¶m_list, editor.make())?;
260
261 if call_info.arguments.len() != params.len() {
262 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, ¶ms, &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 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 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 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 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 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 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 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 for ((pat, param_ty, param), usages, expr) in izip!(params, param_use_nodes, arguments) {
491 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 (None, None) => {}
523 (None, Some(_)) => {
525 this_pat = make.ident_pat(false, true, make.name("this"));
526 }
527 (Some(_), None) => {
529 expr = make.expr_ref(expr, false);
530 }
531 (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 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 [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 [usage] if matches!(expr, ast::Expr::Literal(_)) => {
585 cov_mark::hit!(inline_call_inline_literal);
586 inline_direct(&editor, usage, expr);
587 }
588 [_, ..] 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 _ => {
595 if is_self_param {
596 rewrite_self_to_this(&editor);
598 }
599 insert_let_stmt();
600 }
601 }
602 }
603
604 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 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 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 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}