1use std::{iter, ops::RangeInclusive};
2
3use either::Either;
4use hir::{
5 HasSource, HirDisplay, InFile, Local, LocalSource, ModuleDef, PathResolution, Semantics,
6 TypeInfo, TypeParam,
7};
8use ide_db::{
9 FxIndexSet, RootDatabase,
10 assists::GroupLabel,
11 defs::Definition,
12 famous_defs::FamousDefs,
13 helpers::mod_path_to_ast_with_factory,
14 imports::insert_use::{ImportScope, insert_use_with_editor},
15 search::{FileReference, ReferenceCategory, SearchScope},
16 syntax_helpers::node_ext::{
17 for_each_tail_expr, preorder_expr, walk_pat, walk_patterns_in_expr,
18 },
19};
20use itertools::Itertools;
21use syntax::{
22 Edition, SyntaxElement,
23 SyntaxKind::{self, COMMENT},
24 SyntaxNode, T, TextRange, WalkEvent,
25 ast::{
26 self, AstNode, AstToken, HasAttrs, HasGenericParams, HasName,
27 edit::{AstNodeEdit, IndentLevel},
28 syntax_factory::SyntaxFactory,
29 },
30 match_ast,
31 syntax_editor::{Position, SyntaxEditor},
32};
33
34use crate::{
35 AssistId,
36 assist_context::{AssistContext, Assists},
37 utils::generate_impl_with_item,
38};
39
40pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
68 let range = ctx.selection_trimmed();
69 if range.is_empty() {
70 return None;
71 }
72
73 let node = ctx.covering_element();
74 if matches!(node.kind(), T!['{'] | T!['}'] | T!['('] | T![')'] | T!['['] | T![']']) {
75 cov_mark::hit!(extract_function_in_braces_is_not_applicable);
76 return None;
77 }
78
79 if node.kind() == COMMENT {
80 cov_mark::hit!(extract_function_in_comment_is_not_applicable);
81 return None;
82 }
83
84 let node = match node {
85 syntax::NodeOrToken::Node(n) => n,
86 syntax::NodeOrToken::Token(t) => t.parent()?,
87 };
88
89 let body = extraction_target(&node, range)?;
90
91 let (locals_used, self_param) = body.analyze(&ctx.sema);
92
93 let anchor = if self_param.is_some() { Anchor::Method } else { Anchor::Freestanding };
94 let insert_after = node_to_insert_after(&body, anchor)?;
95 let trait_name = ast::Trait::cast(insert_after.clone()).and_then(|trait_| trait_.name());
96 let semantics_scope = ctx.sema.scope(&insert_after)?;
97 let module = semantics_scope.module();
98 let edition = semantics_scope.krate().edition(ctx.db());
99
100 let (editor, _) = SyntaxEditor::new(ctx.source_file().syntax().clone());
101 let (container_info, contains_tail_expr) =
102 body.analyze_container(editor.make(), &ctx.sema, edition, trait_name)?;
103
104 let ret_ty = body.return_ty(ctx)?;
105 let control_flow = body.external_control_flow(ctx, &container_info)?;
106 let ret_values = body.ret_values(ctx);
107
108 let target_range = body.text_range();
109
110 let scope = ImportScope::find_insert_use_container(&node, &ctx.sema)?;
111
112 acc.add_group(
113 &GroupLabel("Extract into...".to_owned()),
114 AssistId::refactor_extract("extract_function"),
115 "Extract into function",
116 target_range,
117 move |builder| {
118 let make = editor.make();
119 let outliving_locals: Vec<_> = ret_values.collect();
120 if stdx::never!(!outliving_locals.is_empty() && !ret_ty.is_unit()) {
121 return;
123 }
124
125 let params = body.extracted_function_params(ctx, &container_info, locals_used);
126
127 let name = make_function_name(make, &semantics_scope, &body);
128
129 let fun = Function {
130 name,
131 self_param,
132 params,
133 control_flow,
134 ret_ty,
135 body,
136 outliving_locals,
137 contains_tail_expr,
138 mods: container_info,
139 };
140
141 let new_indent = IndentLevel::from_node(&insert_after);
142 let old_indent = fun.body.indent_level();
143
144 let call_expr = make_call(make, ctx, &fun, old_indent);
145
146 let elements = match &fun.body {
147 FunctionBody::Expr(expr) => {
148 let node = SyntaxElement::Node(expr.syntax().clone());
149 node.clone()..=node
150 }
151 FunctionBody::Span { elements, .. } => elements.clone(),
152 };
153
154 let has_impl_wrapper =
155 insert_after.ancestors().any(|a| a.kind() == SyntaxKind::IMPL && a != insert_after);
156
157 let fn_def = format_function(ctx, module, &fun, old_indent, make);
158
159 let fn_def = match fun.self_param_adt(ctx) {
161 Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => {
162 let fn_def = fn_def.indent_with_mapping(1.into(), make);
163
164 let body = make.assoc_item_list([fn_def.into()]);
165 let impl_ = generate_impl_with_item(make, &adt, Some(body)).indent(new_indent);
166
167 impl_.syntax().clone()
168 }
169 _ => fn_def.indent_with_mapping(new_indent, make).syntax().clone(),
170 };
171 if let Some(cap) = ctx.config.snippet_cap {
172 let extracted_fn = fn_def.descendants().find_map(ast::Fn::cast);
173 if let Some(fn_) = extracted_fn {
174 if let Some(ws) = fn_
175 .fn_token()
176 .and_then(|tok| tok.next_token())
177 .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
178 {
179 editor.add_annotation(ws, builder.make_tabstop_after(cap));
180 } else if let Some(name) = fn_.name() {
181 editor.add_annotation(name.syntax(), builder.make_tabstop_before(cap));
182 }
183 }
184 }
185
186 if fun
188 .control_flow
189 .kind
190 .is_some_and(|kind| matches!(kind, FlowKind::Break(_, _) | FlowKind::Continue(_)))
191 {
192 let control_flow_enum =
193 FamousDefs(&ctx.sema, module.krate(ctx.db())).core_ops_ControlFlow();
194
195 if let Some(control_flow_enum) = control_flow_enum {
196 let cfg =
197 ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db)));
198 let mod_path = module.find_use_path(
199 ctx.sema.db,
200 ModuleDef::from(control_flow_enum),
201 ctx.config.insert_use.prefix_kind,
202 cfg,
203 );
204
205 if let Some(mod_path) = mod_path {
206 insert_use_with_editor(
207 &scope,
208 mod_path_to_ast_with_factory(make, &mod_path, edition),
209 &ctx.config.insert_use,
210 &editor,
211 );
212 }
213 }
214 }
215
216 let needs_match_arm_comma = fun
218 .body
219 .parent()
220 .and_then(ast::MatchArm::cast)
221 .is_some_and(|arm| arm.comma_token().is_none());
222 match &fun.body {
223 FunctionBody::Expr(expr) => {
224 let mut replacement = vec![call_expr.clone().into()];
225 if needs_match_arm_comma {
226 replacement.push(make.token(T![,]).into());
227 }
228 editor.replace_with_many(expr.syntax(), replacement);
229 }
230 FunctionBody::Span { .. } => editor.replace_all(elements, vec![call_expr.into()]),
231 }
232
233 editor.insert_all(
235 Position::after(insert_after),
236 vec![make.whitespace(&format!("\n\n{new_indent}")).into(), fn_def.into()],
237 );
238 builder.add_file_edits(ctx.vfs_file_id(), editor);
239 },
240 )
241}
242
243fn make_function_name(
244 make: &SyntaxFactory,
245 semantics_scope: &hir::SemanticsScope<'_>,
246 body: &FunctionBody,
247) -> ast::NameRef {
248 let mut names_in_scope = vec![];
249 semantics_scope.process_all_names(&mut |name, _| {
250 names_in_scope.push(
251 name.display(semantics_scope.db, semantics_scope.krate().edition(semantics_scope.db))
252 .to_string(),
253 )
254 });
255
256 let default_name = "fun_name";
257
258 let mut name = body
259 .suggest_name()
260 .filter(|name| name.len() > 2)
261 .unwrap_or_else(|| default_name.to_owned());
262 let mut counter = 0;
263 while names_in_scope.contains(&name) {
264 counter += 1;
265 name = format!("{default_name}{counter}")
266 }
267 make.name_ref(&name)
268}
269
270fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<FunctionBody> {
288 if let Some(stmt) = ast::Stmt::cast(node.clone()) {
289 return match stmt {
290 ast::Stmt::Item(_) => None,
291 ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => FunctionBody::from_range(
292 node.parent().and_then(ast::StmtList::cast)?,
293 node.text_range(),
294 ),
295 };
296 }
297
298 if let Some(stmt_list) = ast::StmtList::cast(node.clone()) {
300 if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)
301 && block_expr.syntax().text_range() == selection_range
302 {
303 return FunctionBody::from_expr(block_expr.into());
304 }
305
306 return FunctionBody::from_range(stmt_list, selection_range);
308 }
309
310 let expr = ast::Expr::cast(node.clone())?;
311 if node.text_range() == selection_range {
313 return FunctionBody::from_expr(expr);
314 }
315
316 node.ancestors().find_map(ast::Expr::cast).and_then(FunctionBody::from_expr)
317}
318
319#[derive(Debug)]
320struct Function<'db> {
321 name: ast::NameRef,
322 self_param: Option<ast::SelfParam>,
323 params: Vec<Param<'db>>,
324 control_flow: ControlFlow<'db>,
325 ret_ty: RetType<'db>,
326 body: FunctionBody,
327 outliving_locals: Vec<OutlivedLocal>,
328 contains_tail_expr: bool,
330 mods: ContainerInfo<'db>,
331}
332
333#[derive(Debug)]
334struct Param<'db> {
335 var: Local,
336 ty: hir::Type<'db>,
337 move_local: bool,
338 requires_mut: bool,
339 is_copy: bool,
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq)]
343enum ParamKind {
344 Value,
345 MutValue,
346 SharedRef,
347 MutRef,
348}
349
350#[derive(Debug)]
351enum FunType<'db> {
352 Unit,
353 Single(hir::Type<'db>),
354 Tuple(Vec<hir::Type<'db>>),
355}
356
357#[derive(Debug, Eq, PartialEq, Clone, Copy)]
359enum Anchor {
360 Freestanding,
362 Method,
364}
365
366#[derive(Debug)]
369struct ControlFlow<'db> {
370 kind: Option<FlowKind<'db>>,
371 is_async: bool,
372 is_unsafe: bool,
373}
374
375#[derive(Clone, Debug)]
377struct ContainerInfo<'db> {
378 is_const: bool,
379 parent_loop: Option<SyntaxNode>,
380 trait_name: Option<ast::Type>,
381 ret_type: Option<hir::Type<'db>>,
383 generic_param_lists: Vec<ast::GenericParamList>,
384 where_clauses: Vec<ast::WhereClause>,
385 attrs: Vec<ast::Attr>,
386 edition: Edition,
387}
388
389#[derive(Debug, Clone)]
402enum FlowKind<'db> {
403 Return(Option<ast::Expr>),
405 Try {
406 kind: TryKind<'db>,
407 },
408 Break(Option<ast::Lifetime>, Option<ast::Expr>),
410 Continue(Option<ast::Lifetime>),
412}
413
414#[derive(Debug, Clone)]
415enum TryKind<'db> {
416 Option,
417 Result { ty: hir::Type<'db> },
418}
419
420#[derive(Debug)]
421enum RetType<'db> {
422 Expr(hir::Type<'db>),
423 Stmt,
424}
425
426impl RetType<'_> {
427 fn is_unit(&self) -> bool {
428 match self {
429 RetType::Expr(ty) => ty.is_unit(),
430 RetType::Stmt => true,
431 }
432 }
433}
434
435#[derive(Debug)]
438enum FunctionBody {
439 Expr(ast::Expr),
440 Span { parent: ast::StmtList, elements: RangeInclusive<SyntaxElement>, text_range: TextRange },
441}
442
443#[derive(Debug)]
444struct OutlivedLocal {
445 local: Local,
446 mut_usage_outside_body: bool,
447}
448
449struct LocalUsages(ide_db::search::UsageSearchResult);
453
454impl LocalUsages {
455 fn find_local_usages(ctx: &AssistContext<'_, '_>, var: Local) -> Self {
456 Self(
457 Definition::Local(var)
458 .usages(&ctx.sema)
459 .in_scope(&SearchScope::single_file(ctx.file_id()))
460 .all(),
461 )
462 }
463
464 fn iter(&self) -> impl Iterator<Item = &FileReference> + '_ {
465 self.0.iter().flat_map(|(_, rs)| rs)
466 }
467}
468
469impl<'db> Function<'db> {
470 fn return_type(&self, ctx: &AssistContext<'_, 'db>) -> FunType<'db> {
471 match &self.ret_ty {
472 RetType::Expr(ty) if ty.is_unit() => FunType::Unit,
473 RetType::Expr(ty) => FunType::Single(ty.clone()),
474 RetType::Stmt => match self.outliving_locals.as_slice() {
475 [] => FunType::Unit,
476 [var] => FunType::Single(var.local.ty(ctx.db())),
477 vars => {
478 let types = vars.iter().map(|v| v.local.ty(ctx.db())).collect();
479 FunType::Tuple(types)
480 }
481 },
482 }
483 }
484
485 fn self_param_adt(&self, ctx: &AssistContext<'_, '_>) -> Option<ast::Adt> {
486 let self_param = self.self_param.as_ref()?;
487 let def = ctx.sema.to_def(self_param)?;
488 let adt = def.ty(ctx.db()).strip_references().as_adt()?;
489 let InFile { file_id: _, value } = adt.source(ctx.db())?;
490 Some(value)
491 }
492}
493
494impl ParamKind {
495 fn is_ref(&self) -> bool {
496 matches!(self, ParamKind::SharedRef | ParamKind::MutRef)
497 }
498}
499
500impl<'db> Param<'db> {
501 fn kind(&self) -> ParamKind {
502 match (self.move_local, self.requires_mut, self.is_copy) {
503 (false, true, _) => ParamKind::MutRef,
504 (false, false, false) => ParamKind::SharedRef,
505 (true, true, _) => ParamKind::MutValue,
506 (_, false, _) => ParamKind::Value,
507 }
508 }
509
510 fn to_arg(
511 &self,
512 make: &SyntaxFactory,
513 ctx: &AssistContext<'_, 'db>,
514 edition: Edition,
515 ) -> ast::Expr {
516 let var = path_expr_from_local(make, ctx, self.var, edition);
517 match self.kind() {
518 ParamKind::Value | ParamKind::MutValue => var,
519 ParamKind::SharedRef => make.expr_ref(var, false),
520 ParamKind::MutRef => make.expr_ref(var, true),
521 }
522 }
523
524 fn to_param(
525 &self,
526 make: &SyntaxFactory,
527 ctx: &AssistContext<'_, '_>,
528 module: hir::Module,
529 edition: Edition,
530 ) -> ast::Param {
531 let var = self.var.name(ctx.db()).display(ctx.db(), edition).to_string();
532 let var_name = make.name(&var);
533 let pat = match self.kind() {
534 ParamKind::MutValue => make.ident_pat(false, true, var_name),
535 ParamKind::Value | ParamKind::SharedRef | ParamKind::MutRef => {
536 make.simple_ident_pat(var_name)
537 }
538 };
539
540 let ty = make_ty(make, &self.ty, ctx, module);
541 let ty = match self.kind() {
542 ParamKind::Value | ParamKind::MutValue => ty,
543 ParamKind::SharedRef => make.ty_ref(ty, false),
544 ParamKind::MutRef => make.ty_ref(ty, true),
545 };
546
547 make.param(pat.into(), ty)
548 }
549}
550
551impl<'db> TryKind<'db> {
552 fn of_ty(
553 ty: hir::Type<'db>,
554 ctx: &AssistContext<'_, 'db>,
555 edition: Edition,
556 ) -> Option<TryKind<'db>> {
557 if ty.is_unknown() {
558 return Some(TryKind::Result { ty });
560 }
561 let adt = ty.as_adt()?;
562 let name = adt.name(ctx.db());
563 let name = &name.display(ctx.db(), edition).to_string();
566 match name.as_str() {
567 "Option" => Some(TryKind::Option),
568 "Result" => Some(TryKind::Result { ty }),
569 _ => None,
570 }
571 }
572}
573
574impl<'db> FlowKind<'db> {
575 fn make_result_handler(&self, make: &SyntaxFactory, expr: Option<ast::Expr>) -> ast::Expr {
576 match self {
577 FlowKind::Return(_) => make.expr_return(expr).into(),
578 FlowKind::Break(label, _) => make.expr_break(label.clone(), expr).into(),
579 FlowKind::Try { .. } => {
580 stdx::never!("cannot have result handler with try");
581 expr.unwrap_or_else(|| make.expr_return(None).into())
582 }
583 FlowKind::Continue(label) => {
584 stdx::always!(expr.is_none(), "continue with value is not possible");
585 make.expr_continue(label.clone()).into()
586 }
587 }
588 }
589
590 fn expr_ty(&self, ctx: &AssistContext<'_, 'db>) -> Option<hir::Type<'db>> {
591 match self {
592 FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => {
593 ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted)
594 }
595 FlowKind::Try { .. } => {
596 stdx::never!("try does not have defined expr_ty");
597 None
598 }
599 _ => None,
600 }
601 }
602}
603
604impl FunctionBody {
605 fn parent(&self) -> Option<SyntaxNode> {
606 match self {
607 FunctionBody::Expr(expr) => expr.syntax().parent(),
608 FunctionBody::Span { parent, .. } => Some(parent.syntax().clone()),
609 }
610 }
611
612 fn node(&self) -> &SyntaxNode {
613 match self {
614 FunctionBody::Expr(e) => e.syntax(),
615 FunctionBody::Span { parent, .. } => parent.syntax(),
616 }
617 }
618
619 fn extracted_from_trait_impl(&self) -> bool {
620 match self.node().ancestors().find_map(ast::Impl::cast) {
621 Some(c) => c.trait_().is_some(),
622 None => false,
623 }
624 }
625
626 fn descendants(&self) -> impl Iterator<Item = SyntaxNode> {
627 match self {
628 FunctionBody::Expr(expr) => expr.syntax().descendants(),
629 FunctionBody::Span { parent, .. } => parent.syntax().descendants(),
630 }
631 }
632
633 fn descendant_paths(&self) -> impl Iterator<Item = ast::Path> {
634 self.descendants().filter_map(|node| {
635 match_ast! {
636 match node {
637 ast::Path(it) => Some(it),
638 _ => None
639 }
640 }
641 })
642 }
643
644 fn from_expr(expr: ast::Expr) -> Option<Self> {
645 match expr {
646 ast::Expr::BreakExpr(it) => it.expr().map(Self::Expr),
647 ast::Expr::ReturnExpr(it) => it.expr().map(Self::Expr),
648 ast::Expr::BlockExpr(it) if !it.is_standalone() => None,
649 expr => Some(Self::Expr(expr)),
650 }
651 }
652
653 fn from_range(parent: ast::StmtList, selected: TextRange) -> Option<FunctionBody> {
654 let full_body = parent.syntax().children_with_tokens();
655
656 let mut stmts_in_selection = full_body
658 .filter(|it| ast::Stmt::can_cast(it.kind()) || it.kind() == COMMENT)
659 .filter(|it| selected.intersect(it.text_range()).filter(|it| !it.is_empty()).is_some());
660
661 let first_element = stmts_in_selection.next();
662
663 let last_element = if let Some(tail_expr) =
666 parent.tail_expr().filter(|it| selected.intersect(it.syntax().text_range()).is_some())
667 {
668 Some(tail_expr.syntax().clone().into())
669 } else {
670 stmts_in_selection.last()
671 };
672
673 let elements = match (first_element, last_element) {
674 (None, _) => {
675 cov_mark::hit!(extract_function_empty_selection_is_not_applicable);
676 return None;
677 }
678 (Some(first), None) => first.clone()..=first,
679 (Some(first), Some(last)) => first..=last,
680 };
681
682 let text_range = elements.start().text_range().cover(elements.end().text_range());
683
684 Some(Self::Span { parent, elements, text_range })
685 }
686
687 fn indent_level(&self) -> IndentLevel {
688 match &self {
689 FunctionBody::Expr(expr) => IndentLevel::from_node(expr.syntax()),
690 FunctionBody::Span { parent, .. } => IndentLevel::from_node(parent.syntax()) + 1,
691 }
692 }
693
694 fn tail_expr(&self) -> Option<ast::Expr> {
695 match &self {
696 FunctionBody::Expr(expr) => Some(expr.clone()),
697 FunctionBody::Span { parent, text_range, .. } => {
698 let tail_expr = parent.tail_expr()?;
699 text_range.contains_range(tail_expr.syntax().text_range()).then_some(tail_expr)
700 }
701 }
702 }
703
704 fn preorder_expr(&self, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
705 match self {
706 FunctionBody::Expr(expr) => preorder_expr(expr, cb),
707 FunctionBody::Span { parent, text_range, .. } => {
708 parent
709 .statements()
710 .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
711 .filter_map(|stmt| match stmt {
712 ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr().map(|e| vec![e]),
713 ast::Stmt::Item(_) => None,
714 ast::Stmt::LetStmt(stmt) => {
715 let init = stmt.initializer();
716 let let_else = stmt
717 .let_else()
718 .and_then(|le| le.block_expr())
719 .map(ast::Expr::BlockExpr);
720
721 match (init, let_else) {
722 (Some(i), Some(le)) => Some(vec![i, le]),
723 (Some(i), _) => Some(vec![i]),
724 (_, Some(le)) => Some(vec![le]),
725 _ => None,
726 }
727 }
728 })
729 .flatten()
730 .for_each(|expr| preorder_expr(&expr, cb));
731 if let Some(expr) = parent
732 .tail_expr()
733 .filter(|it| text_range.contains_range(it.syntax().text_range()))
734 {
735 preorder_expr(&expr, cb);
736 }
737 }
738 }
739 }
740
741 fn walk_pat(&self, cb: &mut dyn FnMut(ast::Pat)) {
742 match self {
743 FunctionBody::Expr(expr) => walk_patterns_in_expr(expr, cb),
744 FunctionBody::Span { parent, text_range, .. } => {
745 parent
746 .statements()
747 .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
748 .for_each(|stmt| match stmt {
749 ast::Stmt::ExprStmt(expr_stmt) => {
750 if let Some(expr) = expr_stmt.expr() {
751 walk_patterns_in_expr(&expr, cb)
752 }
753 }
754 ast::Stmt::Item(_) => (),
755 ast::Stmt::LetStmt(stmt) => {
756 if let Some(pat) = stmt.pat() {
757 _ = walk_pat(&pat, &mut |pat| {
758 cb(pat);
759 std::ops::ControlFlow::<(), ()>::Continue(())
760 });
761 }
762 if let Some(expr) = stmt.initializer() {
763 walk_patterns_in_expr(&expr, cb);
764 }
765 }
766 });
767 if let Some(expr) = parent
768 .tail_expr()
769 .filter(|it| text_range.contains_range(it.syntax().text_range()))
770 {
771 walk_patterns_in_expr(&expr, cb);
772 }
773 }
774 }
775 }
776
777 fn text_range(&self) -> TextRange {
778 match self {
779 FunctionBody::Expr(expr) => expr.syntax().text_range(),
780 &FunctionBody::Span { text_range, .. } => text_range,
781 }
782 }
783
784 fn contains_range(&self, range: TextRange) -> bool {
785 self.text_range().contains_range(range)
786 }
787
788 fn precedes_range(&self, range: TextRange) -> bool {
789 self.text_range().end() <= range.start()
790 }
791
792 fn contains_node(&self, node: &SyntaxNode) -> bool {
793 self.contains_range(node.text_range())
794 }
795
796 fn suggest_name(&self) -> Option<String> {
797 if let Some(ast::Pat::IdentPat(pat)) = self.parent().and_then(ast::LetStmt::cast)?.pat()
798 && let Some(name) = pat.name().and_then(|it| it.ident_token())
799 {
800 Some(name.text().to_owned())
801 } else {
802 None
803 }
804 }
805}
806
807impl FunctionBody {
808 fn analyze(
811 &self,
812 sema: &Semantics<'_, RootDatabase>,
813 ) -> (FxIndexSet<Local>, Option<ast::SelfParam>) {
814 let mut self_param = None;
815 let mut res = FxIndexSet::default();
816
817 let (text_range, element) = match self {
818 FunctionBody::Expr(expr) => (expr.syntax().text_range(), Either::Left(expr)),
819 FunctionBody::Span { parent, text_range, .. } => (*text_range, Either::Right(parent)),
820 };
821
822 let mut add_name_if_local = |local_ref: Local| {
823 let InFile { file_id, value } = local_ref.primary_source(sema.db).source;
825 if !file_id.is_macro() {
826 match value {
827 Either::Right(it) => {
828 self_param.replace(it);
829 }
830 Either::Left(_) => {
831 res.insert(local_ref);
832 }
833 }
834 }
835 };
836
837 if let Some(locals) = sema.locals_used(element, text_range) {
838 locals.into_iter().for_each(&mut add_name_if_local);
839 }
840
841 (res, self_param)
842 }
843
844 fn analyze_container<'db>(
845 &self,
846 make: &SyntaxFactory,
847 sema: &Semantics<'db, RootDatabase>,
848 edition: Edition,
849 trait_name: Option<ast::Name>,
850 ) -> Option<(ContainerInfo<'db>, bool)> {
851 let mut ancestors = self.parent()?.ancestors();
852 let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
853 let mut parent_loop = None;
854 let mut set_parent_loop = |loop_: &dyn ast::HasLoopBody| {
855 if loop_
856 .loop_body()
857 .is_some_and(|it| it.syntax().text_range().contains_range(self.text_range()))
858 {
859 parent_loop.get_or_insert(loop_.syntax().clone());
860 }
861 };
862
863 let (is_const, expr, ty) = loop {
864 let anc = ancestors.next()?;
865 break match_ast! {
866 match anc {
867 ast::ClosureExpr(closure) => (false, closure.body(), infer_expr_opt(closure.body())),
868 ast::BlockExpr(block_expr) => {
869 let (constness, block) = match block_expr.modifier() {
870 Some(ast::BlockModifier::Const(_)) => (true, block_expr),
871 Some(ast::BlockModifier::Try { .. }) => (false, block_expr),
872 Some(ast::BlockModifier::Label(label)) if label.lifetime().is_some() => (false, block_expr),
873 _ => continue,
874 };
875 let expr = Some(ast::Expr::BlockExpr(block));
876 (constness, expr.clone(), infer_expr_opt(expr))
877 },
878 ast::Fn(fn_) => {
879 let func = sema.to_def(&fn_)?;
880 let mut ret_ty = func.ret_type(sema.db);
881 if func.is_async(sema.db)
882 && let Some(async_ret) = func.async_ret_type(sema.db) {
883 ret_ty = async_ret;
884 }
885 (fn_.const_token().is_some(), fn_.body().map(ast::Expr::BlockExpr), Some(ret_ty))
886 },
887 ast::Static(statik) => {
888 (true, statik.body(), Some(sema.to_def(&statik)?.ty(sema.db)))
889 },
890 ast::ConstArg(ca) => {
891 (true, ca.expr(), infer_expr_opt(ca.expr()))
892 },
893 ast::Const(konst) => {
894 (true, konst.body(), Some(sema.to_def(&konst)?.ty(sema.db)))
895 },
896 ast::ConstParam(cp) => {
897 (true, cp.default_val()?.expr(), Some(sema.to_def(&cp)?.ty(sema.db)))
898 },
899 ast::ConstBlockPat(cbp) => {
900 let expr = cbp.block_expr().map(ast::Expr::BlockExpr);
901 (true, expr.clone(), infer_expr_opt(expr))
902 },
903 ast::Variant(__) => return None,
904 ast::Meta(__) => return None,
905 ast::LoopExpr(it) => {
906 set_parent_loop(&it);
907 continue;
908 },
909 ast::ForExpr(it) => {
910 set_parent_loop(&it);
911 continue;
912 },
913 ast::WhileExpr(it) => {
914 set_parent_loop(&it);
915 continue;
916 },
917 _ => continue,
918 }
919 };
920 };
921
922 let expr = expr?;
923 let contains_tail_expr = if let Some(body_tail) = self.tail_expr() {
924 let mut contains_tail_expr = false;
925 let tail_expr_range = body_tail.syntax().text_range();
926 for_each_tail_expr(&expr, &mut |e| {
927 if tail_expr_range.contains_range(e.syntax().text_range()) {
928 contains_tail_expr = true;
929 }
930 });
931 contains_tail_expr
932 } else {
933 false
934 };
935
936 let trait_name = trait_name.map(|name| make.ty_path(make.ident_path(&name.text())).into());
938
939 let parent = self.parent()?;
940 let parents = generic_parents(&parent);
941 let generic_param_lists = parents.iter().filter_map(|it| it.generic_param_list()).collect();
942 let where_clauses = parents.iter().filter_map(|it| it.where_clause()).collect();
943 let attrs = parents.iter().flat_map(|it| it.attrs()).filter(is_inherit_attr).collect();
944
945 Some((
946 ContainerInfo {
947 is_const,
948 parent_loop,
949 trait_name,
950 ret_type: ty,
951 generic_param_lists,
952 where_clauses,
953 attrs,
954 edition,
955 },
956 contains_tail_expr,
957 ))
958 }
959
960 fn return_ty<'db>(&self, ctx: &AssistContext<'_, 'db>) -> Option<RetType<'db>> {
961 match self.tail_expr() {
962 Some(expr) => ctx.sema.type_of_expr(&expr).map(TypeInfo::original).map(RetType::Expr),
963 None => Some(RetType::Stmt),
964 }
965 }
966
967 fn ret_values<'a>(
969 &self,
970 ctx: &'a AssistContext<'_, '_>,
971 ) -> impl Iterator<Item = OutlivedLocal> + 'a {
972 let range = self.text_range();
973 locals_defined_in_body(&ctx.sema, self)
974 .into_iter()
975 .filter_map(move |local| local_outlives_body(ctx, range, local))
976 }
977
978 fn external_control_flow<'db>(
980 &self,
981 ctx: &AssistContext<'_, 'db>,
982 container_info: &ContainerInfo<'db>,
983 ) -> Option<ControlFlow<'db>> {
984 let mut ret_expr = None;
985 let mut try_expr = None;
986 let mut break_expr = None;
987 let mut continue_expr = None;
988 let mut is_async = false;
989 let mut _is_unsafe = false;
990
991 let mut unsafe_depth = 0;
992 let mut loop_depth = 0;
993
994 self.preorder_expr(&mut |expr| {
995 let expr = match expr {
996 WalkEvent::Enter(e) => e,
997 WalkEvent::Leave(expr) => {
998 match expr {
999 ast::Expr::LoopExpr(_)
1000 | ast::Expr::ForExpr(_)
1001 | ast::Expr::WhileExpr(_) => loop_depth -= 1,
1002 ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => {
1003 unsafe_depth -= 1
1004 }
1005 _ => (),
1006 }
1007 return false;
1008 }
1009 };
1010 match expr {
1011 ast::Expr::LoopExpr(_) | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) => {
1012 loop_depth += 1;
1013 }
1014 ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => {
1015 unsafe_depth += 1
1016 }
1017 ast::Expr::ReturnExpr(it) => {
1018 ret_expr = Some(it);
1019 }
1020 ast::Expr::TryExpr(it) => {
1021 try_expr = Some(it);
1022 }
1023 ast::Expr::BreakExpr(it) if loop_depth == 0 => {
1024 break_expr = Some(it);
1025 }
1026 ast::Expr::ContinueExpr(it) if loop_depth == 0 => {
1027 continue_expr = Some(it);
1028 }
1029 ast::Expr::AwaitExpr(_) => is_async = true,
1030 _ => {}
1034 }
1035 false
1036 });
1037
1038 let kind = match (try_expr, ret_expr, break_expr, continue_expr) {
1039 (Some(_), _, None, None) => {
1040 let ret_ty = container_info.ret_type.clone()?;
1041 let kind = TryKind::of_ty(ret_ty, ctx, container_info.edition)?;
1042
1043 Some(FlowKind::Try { kind })
1044 }
1045 (Some(_), _, _, _) => {
1046 cov_mark::hit!(external_control_flow_try_and_bc);
1047 return None;
1048 }
1049 (None, Some(r), None, None) => Some(FlowKind::Return(r.expr())),
1050 (None, Some(_), _, _) => {
1051 cov_mark::hit!(external_control_flow_return_and_bc);
1052 return None;
1053 }
1054 (None, None, Some(_), Some(_)) => {
1055 cov_mark::hit!(external_control_flow_break_and_continue);
1056 return None;
1057 }
1058 (None, None, Some(b), None) => Some(FlowKind::Break(b.lifetime(), b.expr())),
1059 (None, None, None, Some(c)) => Some(FlowKind::Continue(c.lifetime())),
1060 (None, None, None, None) => None,
1061 };
1062
1063 Some(ControlFlow { kind, is_async, is_unsafe: _is_unsafe })
1064 }
1065
1066 fn extracted_function_params<'db>(
1070 &self,
1071 ctx: &AssistContext<'_, 'db>,
1072 container_info: &ContainerInfo<'db>,
1073 locals: FxIndexSet<Local>,
1074 ) -> Vec<Param<'db>> {
1075 locals
1076 .into_iter()
1077 .sorted()
1078 .map(|local| (local, local.primary_source(ctx.db())))
1079 .filter(|(_, src)| is_defined_outside_of_body(ctx, self, src))
1080 .filter_map(|(local, src)| match src.into_ident_pat() {
1081 Some(src) => Some((local, src)),
1082 None => {
1083 stdx::never!(false, "Local::is_self returned false, but source is SelfParam");
1084 None
1085 }
1086 })
1087 .map(|(var, src)| {
1088 let usages = LocalUsages::find_local_usages(ctx, var);
1089 let ty = var.ty(ctx.db());
1090
1091 let defined_outside_parent_loop = container_info
1092 .parent_loop
1093 .as_ref()
1094 .is_none_or(|it| it.text_range().contains_range(src.syntax().text_range()));
1095
1096 let is_copy = ty.is_copy(ctx.db());
1097 let has_usages = self.has_usages_after_body(&usages);
1098 let requires_mut =
1099 !ty.is_mutable_reference() && has_exclusive_usages(ctx, &usages, self);
1100 let move_local = (!has_usages && defined_outside_parent_loop) || ty.is_reference();
1104 Param { var, ty, move_local, requires_mut, is_copy }
1105 })
1106 .collect()
1107 }
1108
1109 fn has_usages_after_body(&self, usages: &LocalUsages) -> bool {
1110 usages.iter().any(|reference| self.precedes_range(reference.range))
1111 }
1112}
1113
1114enum GenericParent {
1115 Fn(ast::Fn),
1116 Impl(ast::Impl),
1117 Trait(ast::Trait),
1118}
1119
1120impl GenericParent {
1121 fn generic_param_list(&self) -> Option<ast::GenericParamList> {
1122 match self {
1123 GenericParent::Fn(fn_) => fn_.generic_param_list(),
1124 GenericParent::Impl(impl_) => impl_.generic_param_list(),
1125 GenericParent::Trait(trait_) => trait_.generic_param_list(),
1126 }
1127 }
1128
1129 fn where_clause(&self) -> Option<ast::WhereClause> {
1130 match self {
1131 GenericParent::Fn(fn_) => fn_.where_clause(),
1132 GenericParent::Impl(impl_) => impl_.where_clause(),
1133 GenericParent::Trait(trait_) => trait_.where_clause(),
1134 }
1135 }
1136
1137 fn attrs(&self) -> impl Iterator<Item = ast::Attr> {
1138 match self {
1139 GenericParent::Fn(fn_) => fn_.attrs(),
1140 GenericParent::Impl(impl_) => impl_.attrs(),
1141 GenericParent::Trait(trait_) => trait_.attrs(),
1142 }
1143 }
1144}
1145
1146fn generic_parents(parent: &SyntaxNode) -> Vec<GenericParent> {
1148 let mut list = Vec::new();
1149 if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast)
1150 && let ast::Item::Fn(ref fn_) = parent_item
1151 {
1152 if let Some(parent_parent) =
1153 parent_item.syntax().parent().and_then(|it| it.parent()).and_then(ast::Item::cast)
1154 {
1155 match parent_parent {
1156 ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)),
1157 ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)),
1158 _ => (),
1159 }
1160 }
1161 list.push(GenericParent::Fn(fn_.clone()));
1162 }
1163 list
1164}
1165
1166fn has_exclusive_usages(
1168 ctx: &AssistContext<'_, '_>,
1169 usages: &LocalUsages,
1170 body: &FunctionBody,
1171) -> bool {
1172 usages
1173 .iter()
1174 .filter(|reference| body.contains_range(reference.range))
1175 .any(|reference| reference_is_exclusive(reference, ctx))
1176}
1177
1178fn reference_is_exclusive(reference: &FileReference, ctx: &AssistContext<'_, '_>) -> bool {
1180 if reference.category.contains(ReferenceCategory::WRITE) {
1188 return true;
1189 }
1190
1191 let path = match path_element_of(reference) {
1193 Some(path) => path,
1194 None => return false,
1195 };
1196
1197 expr_require_exclusive_access(ctx, &path).unwrap_or(false)
1198}
1199
1200fn expr_require_exclusive_access(ctx: &AssistContext<'_, '_>, expr: &ast::Expr) -> Option<bool> {
1202 let parent = expr.syntax().parent()?;
1203
1204 if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) {
1205 if matches!(bin_expr.op_kind()?, ast::BinaryOp::Assignment { .. }) {
1206 return Some(bin_expr.lhs()?.syntax() == expr.syntax());
1207 }
1208 return Some(false);
1209 }
1210
1211 if let Some(ref_expr) = ast::RefExpr::cast(parent.clone()) {
1212 return Some(ref_expr.mut_token().is_some());
1213 }
1214
1215 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
1216 let func = ctx.sema.resolve_method_call(&method_call)?;
1217 let self_param = func.self_param(ctx.db())?;
1218 let access = self_param.access(ctx.db());
1219
1220 return Some(matches!(access, hir::Access::Exclusive));
1221 }
1222
1223 if let Some(field) = ast::FieldExpr::cast(parent) {
1224 return expr_require_exclusive_access(ctx, &field.into());
1225 }
1226
1227 Some(false)
1228}
1229
1230fn path_element_of(reference: &FileReference) -> Option<ast::Expr> {
1236 let path = reference.name.syntax().ancestors().find_map(ast::Expr::cast).or_else(|| {
1237 stdx::never!(false, "cannot find path parent of variable usage: {:?}", reference.name);
1238 None
1239 })?;
1240 stdx::always!(
1241 matches!(path, ast::Expr::PathExpr(_))
1242 || path.syntax().parent().and_then(ast::FormatArgsExpr::cast).is_some(),
1243 "unexpected expression type for variable usage: {:?}",
1244 path
1245 );
1246 Some(path)
1247}
1248
1249fn locals_defined_in_body(
1251 sema: &Semantics<'_, RootDatabase>,
1252 body: &FunctionBody,
1253) -> FxIndexSet<Local> {
1254 let mut res = FxIndexSet::default();
1257 body.walk_pat(&mut |pat| {
1258 if let ast::Pat::IdentPat(pat) = pat
1259 && let Some(local) = sema.to_def(&pat)
1260 {
1261 res.insert(local);
1262 }
1263 });
1264 res
1265}
1266
1267fn local_outlives_body(
1269 ctx: &AssistContext<'_, '_>,
1270 body_range: TextRange,
1271 local: Local,
1272) -> Option<OutlivedLocal> {
1273 let usages = LocalUsages::find_local_usages(ctx, local);
1274 let mut has_mut_usages = false;
1275 let mut any_outlives = false;
1276 for usage in usages.iter() {
1277 if body_range.end() <= usage.range.start() {
1278 has_mut_usages |= reference_is_exclusive(usage, ctx);
1279 any_outlives |= true;
1280 if has_mut_usages {
1281 break; }
1283 }
1284 }
1285 if !any_outlives {
1286 return None;
1287 }
1288 Some(OutlivedLocal { local, mut_usage_outside_body: has_mut_usages })
1289}
1290
1291fn is_defined_outside_of_body(
1293 ctx: &AssistContext<'_, '_>,
1294 body: &FunctionBody,
1295 src: &LocalSource,
1296) -> bool {
1297 src.original_file(ctx.db()) == ctx.file_id() && !body.contains_node(src.syntax())
1298}
1299
1300fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option<SyntaxNode> {
1304 let node = body.node();
1305 let mut ancestors = node.ancestors().peekable();
1306 let mut last_ancestor = None;
1307 while let Some(next_ancestor) = ancestors.next() {
1308 match next_ancestor.kind() {
1309 SyntaxKind::SOURCE_FILE => break,
1310 SyntaxKind::IMPL
1311 if body.extracted_from_trait_impl() && matches!(anchor, Anchor::Method) =>
1312 {
1313 let impl_node = find_non_trait_impl(&next_ancestor);
1314 if let target_node @ Some(_) = impl_node.as_ref().and_then(last_impl_member) {
1315 return target_node;
1316 }
1317 }
1318 SyntaxKind::ITEM_LIST if !matches!(anchor, Anchor::Freestanding) => continue,
1319 SyntaxKind::ITEM_LIST
1320 if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::MODULE) =>
1321 {
1322 break;
1323 }
1324 SyntaxKind::ASSOC_ITEM_LIST if !matches!(anchor, Anchor::Method) => continue,
1325 SyntaxKind::ASSOC_ITEM_LIST if body.extracted_from_trait_impl() => continue,
1326 SyntaxKind::ASSOC_ITEM_LIST
1327 if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::IMPL) =>
1328 {
1329 break;
1330 }
1331 _ => (),
1332 }
1333 last_ancestor = Some(next_ancestor);
1334 }
1335 last_ancestor
1336}
1337
1338fn find_non_trait_impl(trait_impl: &SyntaxNode) -> Option<ast::Impl> {
1339 let as_impl = ast::Impl::cast(trait_impl.clone())?;
1340 let impl_type = Some(impl_type_name(&as_impl)?);
1341
1342 let siblings = trait_impl.parent()?.children();
1343 siblings
1344 .filter_map(ast::Impl::cast)
1345 .find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s))
1346}
1347
1348fn last_impl_member(impl_node: &ast::Impl) -> Option<SyntaxNode> {
1349 let last_child = impl_node.assoc_item_list()?.assoc_items().last()?;
1350 Some(last_child.syntax().clone())
1351}
1352
1353fn is_trait_impl(node: &ast::Impl) -> bool {
1354 node.trait_().is_some()
1355}
1356
1357fn impl_type_name(impl_node: &ast::Impl) -> Option<String> {
1358 Some(impl_node.self_ty()?.to_string())
1359}
1360
1361fn make_call<'db>(
1362 make: &SyntaxFactory,
1363 ctx: &AssistContext<'_, 'db>,
1364 fun: &Function<'db>,
1365 indent: IndentLevel,
1366) -> SyntaxNode {
1367 let ret_ty = fun.return_type(ctx);
1368
1369 let name = fun.name.clone();
1370 let args = fun.params.iter().map(|param| param.to_arg(make, ctx, fun.mods.edition));
1371 let mut call_expr = if fun.make_this_param().is_some() {
1372 let self_arg = make.expr_path(make.ident_path("self"));
1373 let func = make.expr_path(make.path_unqualified(make.path_segment(name)));
1374 make.expr_call(func, make.arg_list(Some(self_arg).into_iter().chain(args))).into()
1375 } else if fun.self_param.is_some() {
1376 let self_arg = make.expr_path(make.ident_path("self"));
1377 make.expr_method_call(self_arg, name, make.arg_list(args)).into()
1378 } else {
1379 let func = make.expr_path(make.path_unqualified(make.path_segment(name)));
1380 make.expr_call(func, make.arg_list(args)).into()
1381 };
1382
1383 let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
1384
1385 if fun.control_flow.is_async {
1386 call_expr = make.expr_await(call_expr).into();
1387 }
1388
1389 let expr = handler.make_call_expr(make, call_expr).indent_with_mapping(indent, make);
1390
1391 let outliving_bindings = match fun.outliving_locals.as_slice() {
1392 [] => None,
1393 [var] => {
1394 let name = var.local.name(ctx.db());
1395 let name = make.name(&name.display(ctx.db(), fun.mods.edition).to_string());
1396 Some(ast::Pat::IdentPat(make.ident_pat(false, var.mut_usage_outside_body, name)))
1397 }
1398 vars => {
1399 let binding_pats = vars.iter().map(|var| {
1400 let name = var.local.name(ctx.db());
1401 let name = make.name(&name.display(ctx.db(), fun.mods.edition).to_string());
1402 make.ident_pat(false, var.mut_usage_outside_body, name).into()
1403 });
1404 Some(ast::Pat::TuplePat(make.tuple_pat(binding_pats)))
1405 }
1406 };
1407
1408 let parent_match_arm = fun.body.parent().and_then(ast::MatchArm::cast);
1409
1410 if let Some(bindings) = outliving_bindings {
1411 make.let_stmt(bindings, None, Some(expr)).syntax().clone()
1413 } else if parent_match_arm.as_ref().is_some() {
1414 expr.syntax().clone()
1416 } else if parent_match_arm.as_ref().is_none()
1417 && fun.ret_ty.is_unit()
1418 && (!fun.outliving_locals.is_empty() || !expr.is_block_like())
1419 {
1420 make.expr_stmt(expr).syntax().clone()
1422 } else {
1423 expr.syntax().clone()
1425 }
1426}
1427
1428enum FlowHandler<'db> {
1429 None,
1430 Try { kind: TryKind<'db> },
1431 If { action: FlowKind<'db> },
1432 IfOption { action: FlowKind<'db> },
1433 MatchOption { none: FlowKind<'db> },
1434 MatchResult { err: FlowKind<'db> },
1435}
1436
1437impl<'db> FlowHandler<'db> {
1438 fn from_ret_ty(fun: &Function<'db>, ret_ty: &FunType<'db>) -> FlowHandler<'db> {
1439 if fun.contains_tail_expr {
1440 return FlowHandler::None;
1441 }
1442 let Some(action) = fun.control_flow.kind.clone() else {
1443 return FlowHandler::None;
1444 };
1445
1446 if let FunType::Unit = ret_ty {
1447 match action {
1448 FlowKind::Return(None) | FlowKind::Break(_, None) | FlowKind::Continue(_) => {
1449 FlowHandler::If { action }
1450 }
1451 FlowKind::Return(_) | FlowKind::Break(_, _) => FlowHandler::IfOption { action },
1452 FlowKind::Try { kind } => FlowHandler::Try { kind },
1453 }
1454 } else {
1455 match action {
1456 FlowKind::Return(None) | FlowKind::Break(_, None) | FlowKind::Continue(_) => {
1457 FlowHandler::MatchOption { none: action }
1458 }
1459 FlowKind::Return(_) | FlowKind::Break(_, _) => {
1460 FlowHandler::MatchResult { err: action }
1461 }
1462 FlowKind::Try { kind } => FlowHandler::Try { kind },
1463 }
1464 }
1465 }
1466
1467 fn make_call_expr(&self, make: &SyntaxFactory, call_expr: ast::Expr) -> ast::Expr {
1468 match self {
1469 FlowHandler::None => call_expr,
1470 FlowHandler::Try { kind: _ } => make.expr_try(call_expr),
1471 FlowHandler::If { action } => {
1472 let action = action.make_result_handler(make, None);
1473 let stmt = make.expr_stmt(action);
1474 let block = make.block_expr(iter::once(stmt.into()), None);
1475 let controlflow_break_path = make.path_from_text("ControlFlow::Break");
1476 let condition = make.expr_let(
1477 make.tuple_struct_pat(
1478 controlflow_break_path,
1479 iter::once(make.wildcard_pat().into()),
1480 )
1481 .into(),
1482 call_expr,
1483 );
1484 make.expr_if(condition.into(), block, None).into()
1485 }
1486 FlowHandler::IfOption { action } => {
1487 let path = make.ident_path("Some");
1488 let value_pat = make.simple_ident_pat(make.name("value"));
1489 let pattern = make.tuple_struct_pat(path, iter::once(value_pat.into()));
1490 let cond = make.expr_let(pattern.into(), call_expr);
1491 let value = make.expr_path(make.ident_path("value"));
1492 let action_expr = action.make_result_handler(make, Some(value));
1493 let action_stmt = make.expr_stmt(action_expr);
1494 let then = make.block_expr(iter::once(action_stmt.into()), None);
1495 make.expr_if(cond.into(), then, None).into()
1496 }
1497 FlowHandler::MatchOption { none } => {
1498 let some_name = "value";
1499
1500 let some_arm = {
1501 let path = make.ident_path("Some");
1502 let value_pat = make.simple_ident_pat(make.name(some_name));
1503 let pat = make.tuple_struct_pat(path, iter::once(value_pat.into()));
1504 let value = make.expr_path(make.ident_path(some_name));
1505 make.match_arm(pat.into(), None, value)
1506 };
1507 let none_arm = {
1508 let path = make.ident_path("None");
1509 let pat = make.path_pat(path);
1510 make.match_arm(pat, None, none.make_result_handler(make, None))
1511 };
1512 let arms = make.match_arm_list(vec![some_arm, none_arm]);
1513 make.expr_match(call_expr, arms).into()
1514 }
1515 FlowHandler::MatchResult { err } => {
1516 let ok_name = "value";
1517 let err_name = "value";
1518
1519 let ok_arm = {
1520 let path = make.ident_path("Ok");
1521 let value_pat = make.simple_ident_pat(make.name(ok_name));
1522 let pat = make.tuple_struct_pat(path, iter::once(value_pat.into()));
1523 let value = make.expr_path(make.ident_path(ok_name));
1524 make.match_arm(pat.into(), None, value)
1525 };
1526 let err_arm = {
1527 let path = make.ident_path("Err");
1528 let value_pat = make.simple_ident_pat(make.name(err_name));
1529 let pat = make.tuple_struct_pat(path, iter::once(value_pat.into()));
1530 let value = make.expr_path(make.ident_path(err_name));
1531 make.match_arm(pat.into(), None, err.make_result_handler(make, Some(value)))
1532 };
1533 let arms = make.match_arm_list(vec![ok_arm, err_arm]);
1534 make.expr_match(call_expr, arms).into()
1535 }
1536 }
1537 }
1538}
1539
1540fn path_expr_from_local(
1541 make: &SyntaxFactory,
1542 ctx: &AssistContext<'_, '_>,
1543 var: Local,
1544 edition: Edition,
1545) -> ast::Expr {
1546 let name = var.name(ctx.db()).display(ctx.db(), edition).to_string();
1547 make.expr_path(make.ident_path(&name))
1548}
1549
1550fn format_function<'db>(
1551 ctx: &AssistContext<'_, 'db>,
1552 module: hir::Module,
1553 fun: &Function<'db>,
1554 old_indent: IndentLevel,
1555 make: &SyntaxFactory,
1556) -> ast::Fn {
1557 let fun_name = make.name(&fun.name.text());
1558 let params = fun.make_param_list(make, ctx, module, fun.mods.edition);
1559 let ret_ty = fun.make_ret_ty(make, ctx, module);
1560 let body = make_body(make, ctx, old_indent, fun);
1561 let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, make, fun);
1562
1563 make.fn_(
1564 fun.mods.attrs.clone(),
1565 None,
1566 fun_name.clone(),
1567 generic_params,
1568 where_clause,
1569 params,
1570 body,
1571 ret_ty,
1572 fun.control_flow.is_async,
1573 fun.mods.is_const,
1574 fun.control_flow.is_unsafe,
1575 false,
1576 )
1577}
1578
1579fn make_generic_params_and_where_clause<'db>(
1580 ctx: &AssistContext<'_, 'db>,
1581 make: &SyntaxFactory,
1582 fun: &Function<'db>,
1583) -> (Option<ast::GenericParamList>, Option<ast::WhereClause>) {
1584 let used_type_params = fun.type_params(ctx);
1585
1586 let generic_param_list = make_generic_param_list(ctx, make, fun, &used_type_params);
1587 let where_clause = make_where_clause(ctx, make, fun, &used_type_params);
1588
1589 (generic_param_list, where_clause)
1590}
1591
1592fn make_generic_param_list<'db>(
1593 ctx: &AssistContext<'_, 'db>,
1594 make: &SyntaxFactory,
1595 fun: &Function<'db>,
1596 used_type_params: &[TypeParam],
1597) -> Option<ast::GenericParamList> {
1598 let mut generic_params = fun
1599 .mods
1600 .generic_param_lists
1601 .iter()
1602 .flat_map(|parent_params| {
1603 parent_params
1604 .generic_params()
1605 .filter(|param| param_is_required(ctx, param, used_type_params))
1606 })
1607 .peekable();
1608
1609 if generic_params.peek().is_some() {
1610 Some(make.generic_param_list(generic_params))
1611 } else {
1612 None
1613 }
1614}
1615
1616fn param_is_required(
1617 ctx: &AssistContext<'_, '_>,
1618 param: &ast::GenericParam,
1619 used_type_params: &[TypeParam],
1620) -> bool {
1621 match param {
1622 ast::GenericParam::ConstParam(_) | ast::GenericParam::LifetimeParam(_) => false,
1623 ast::GenericParam::TypeParam(type_param) => match &ctx.sema.to_def(type_param) {
1624 Some(def) => used_type_params.contains(def),
1625 _ => false,
1626 },
1627 }
1628}
1629
1630fn make_where_clause(
1631 ctx: &AssistContext<'_, '_>,
1632 make: &SyntaxFactory,
1633 fun: &Function<'_>,
1634 used_type_params: &[TypeParam],
1635) -> Option<ast::WhereClause> {
1636 let mut predicates = fun
1637 .mods
1638 .where_clauses
1639 .iter()
1640 .flat_map(|parent_where_clause| {
1641 parent_where_clause
1642 .predicates()
1643 .filter(|pred| pred_is_required(ctx, pred, used_type_params))
1644 })
1645 .peekable();
1646
1647 if predicates.peek().is_some() { Some(make.where_clause(predicates)) } else { None }
1648}
1649
1650fn pred_is_required(
1651 ctx: &AssistContext<'_, '_>,
1652 pred: &ast::WherePred,
1653 used_type_params: &[TypeParam],
1654) -> bool {
1655 match resolved_type_param(ctx, pred) {
1656 Some(it) => used_type_params.contains(&it),
1657 None => false,
1658 }
1659}
1660
1661fn resolved_type_param(ctx: &AssistContext<'_, '_>, pred: &ast::WherePred) -> Option<TypeParam> {
1662 let path = match pred.ty()? {
1663 ast::Type::PathType(path_type) => path_type.path(),
1664 _ => None,
1665 }?;
1666
1667 match ctx.sema.resolve_path(&path)? {
1668 PathResolution::TypeParam(type_param) => Some(type_param),
1669 _ => None,
1670 }
1671}
1672
1673impl<'db> Function<'db> {
1674 fn type_params(&self, ctx: &AssistContext<'_, 'db>) -> Vec<TypeParam> {
1676 let type_params_in_descendant_paths =
1677 self.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) {
1678 Some(PathResolution::TypeParam(type_param)) => Some(type_param),
1679 _ => None,
1680 });
1681 let type_params_in_params = self.params.iter().filter_map(|p| p.ty.as_type_param(ctx.db()));
1682 type_params_in_descendant_paths.chain(type_params_in_params).collect()
1683 }
1684
1685 fn make_param_list(
1686 &self,
1687 make: &SyntaxFactory,
1688 ctx: &AssistContext<'_, '_>,
1689 module: hir::Module,
1690 edition: Edition,
1691 ) -> ast::ParamList {
1692 let this_param = self.make_this_param().map(|f| f(make));
1693 let self_param = self.self_param.clone().filter(|_| this_param.is_none());
1694 let params = self.params.iter().map(|param| param.to_param(make, ctx, module, edition));
1695 make.param_list(self_param, this_param.into_iter().chain(params))
1696 }
1697
1698 fn make_this_param(&self) -> Option<impl FnOnce(&SyntaxFactory) -> ast::Param> {
1699 if let Some(name) = self.mods.trait_name.clone()
1700 && let Some(self_param) = &self.self_param
1701 {
1702 Some(move |make: &SyntaxFactory| {
1703 let bounds = make.type_bound_list([make.type_bound(name)]);
1704 let pat = make.path_pat(make.ident_path("this"));
1705 let mut ty = make.impl_trait_type(bounds.unwrap()).into();
1706 if self_param.amp_token().is_some() {
1707 ty = make.ty_ref(ty, self_param.mut_token().is_some());
1708 }
1709 make.param(pat, ty)
1710 })
1711 } else {
1712 None
1713 }
1714 }
1715
1716 fn make_ret_ty(
1717 &self,
1718 make: &SyntaxFactory,
1719 ctx: &AssistContext<'_, 'db>,
1720 module: hir::Module,
1721 ) -> Option<ast::RetType> {
1722 let fun_ty = self.return_type(ctx);
1723 let handler = FlowHandler::from_ret_ty(self, &fun_ty);
1724 let ret_ty = match &handler {
1725 FlowHandler::None => {
1726 if matches!(fun_ty, FunType::Unit) {
1727 return None;
1728 }
1729 fun_ty.make_ty(make, ctx, module)
1730 }
1731 FlowHandler::Try { kind: TryKind::Option } => {
1732 make.ty_option(fun_ty.make_ty(make, ctx, module)).into()
1733 }
1734 FlowHandler::Try { kind: TryKind::Result { ty: parent_ret_ty } } => {
1735 let handler_ty = parent_ret_ty
1736 .type_arguments()
1737 .nth(1)
1738 .map(|ty| make_ty(make, &ty, ctx, module))
1739 .unwrap_or_else(|| make.ty_placeholder());
1740 make.ty_result(fun_ty.make_ty(make, ctx, module), handler_ty).into()
1741 }
1742 FlowHandler::If { .. } => make.ty("ControlFlow<()>"),
1743 FlowHandler::IfOption { action } => {
1744 let handler_ty = action
1745 .expr_ty(ctx)
1746 .map(|ty| make_ty(make, &ty, ctx, module))
1747 .unwrap_or_else(|| make.ty_placeholder());
1748 make.ty_option(handler_ty).into()
1749 }
1750 FlowHandler::MatchOption { .. } => {
1751 make.ty_option(fun_ty.make_ty(make, ctx, module)).into()
1752 }
1753 FlowHandler::MatchResult { err } => {
1754 let handler_ty = err
1755 .expr_ty(ctx)
1756 .map(|ty| make_ty(make, &ty, ctx, module))
1757 .unwrap_or_else(|| make.ty_placeholder());
1758 make.ty_result(fun_ty.make_ty(make, ctx, module), handler_ty).into()
1759 }
1760 };
1761 Some(make.ret_type(ret_ty))
1762 }
1763}
1764
1765impl<'db> FunType<'db> {
1766 fn make_ty(
1767 &self,
1768 make: &SyntaxFactory,
1769 ctx: &AssistContext<'_, 'db>,
1770 module: hir::Module,
1771 ) -> ast::Type {
1772 match self {
1773 FunType::Unit => make.ty_unit(),
1774 FunType::Single(ty) => make_ty(make, ty, ctx, module),
1775 FunType::Tuple(types) => match types.as_slice() {
1776 [] => {
1777 stdx::never!("tuple type with 0 elements");
1778 make.ty_unit()
1779 }
1780 [ty] => {
1781 stdx::never!("tuple type with 1 element");
1782 make_ty(make, ty, ctx, module)
1783 }
1784 types => {
1785 let types = types.iter().map(|ty| make_ty(make, ty, ctx, module));
1786 make.ty_tuple(types)
1787 }
1788 },
1789 }
1790 }
1791}
1792
1793fn make_body<'db>(
1794 make: &SyntaxFactory,
1795 ctx: &AssistContext<'_, 'db>,
1796 old_indent: IndentLevel,
1797 fun: &Function<'db>,
1798) -> ast::BlockExpr {
1799 let ret_ty = fun.return_type(ctx);
1800 let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
1801 let to_this_param = fun.self_param.clone().filter(|_| fun.make_this_param().is_some());
1802
1803 let block = match &fun.body {
1804 FunctionBody::Expr(expr) => {
1805 let expr =
1806 rewrite_body_segment(ctx, to_this_param, &fun.params, &handler, expr.syntax());
1807 let expr = ast::Expr::cast(expr).expect("Body segment should be an expr");
1808 match expr {
1809 ast::Expr::BlockExpr(block) => {
1810 let block = block.dedent(old_indent);
1812 let elements = block.stmt_list().map_or_else(
1813 || Either::Left(iter::empty()),
1814 |stmt_list| {
1815 let elements = stmt_list.syntax().children_with_tokens().filter_map(
1816 |node_or_token| match &node_or_token {
1817 syntax::NodeOrToken::Node(node) => {
1818 ast::Stmt::cast(node.clone()).map(|_| node_or_token)
1819 }
1820 syntax::NodeOrToken::Token(token) => {
1821 ast::Comment::cast(token.clone()).map(|_| node_or_token)
1822 }
1823 },
1824 );
1825 Either::Right(elements)
1826 },
1827 );
1828 make.hacky_block_expr(elements, block.tail_expr())
1829 }
1830 _ => {
1831 let expr = expr.dedent(old_indent).indent(1.into());
1832
1833 make.block_expr(Vec::new(), Some(expr))
1834 }
1835 }
1836 }
1837 FunctionBody::Span { parent, text_range, .. } => {
1838 let mut elements: Vec<_> = parent
1839 .syntax()
1840 .children_with_tokens()
1841 .filter(|it| text_range.contains_range(it.text_range()))
1842 .map(|it| match &it {
1843 syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
1844 rewrite_body_segment(ctx, to_this_param.clone(), &fun.params, &handler, n),
1845 ),
1846 _ => it,
1847 })
1848 .collect();
1849
1850 let mut tail_expr = match &elements.last() {
1851 Some(syntax::NodeOrToken::Node(node)) if ast::Expr::can_cast(node.kind()) => {
1852 ast::Expr::cast(node.clone())
1853 }
1854 _ => None,
1855 };
1856
1857 match tail_expr {
1858 Some(_) => {
1859 elements.pop();
1860 }
1861 None => match fun.outliving_locals.as_slice() {
1862 [] => {}
1863 [var] => {
1864 tail_expr =
1865 Some(path_expr_from_local(make, ctx, var.local, fun.mods.edition));
1866 }
1867 vars => {
1868 let exprs = vars.iter().map(|var| {
1869 path_expr_from_local(make, ctx, var.local, fun.mods.edition)
1870 });
1871 let expr = make.expr_tuple(exprs);
1872 tail_expr = Some(expr.into());
1873 }
1874 },
1875 };
1876
1877 let body_indent = IndentLevel(1);
1878 let elements = elements
1879 .into_iter()
1880 .map(|node_or_token| match &node_or_token {
1881 syntax::NodeOrToken::Node(node) => match ast::Stmt::cast(node.clone()) {
1882 Some(stmt) => {
1883 let stmt = stmt.dedent(old_indent).indent(body_indent);
1884 syntax::NodeOrToken::Node(stmt.syntax().clone())
1885 }
1886 _ => node_or_token,
1887 },
1888 _ => node_or_token,
1889 })
1890 .collect::<Vec<SyntaxElement>>();
1891 tail_expr = tail_expr.map(|expr| expr.dedent(old_indent).indent(body_indent));
1892
1893 make.hacky_block_expr(elements, tail_expr)
1894 }
1895 };
1896
1897 match &handler {
1898 FlowHandler::None => block,
1899 FlowHandler::Try { kind } => {
1900 let block = with_default_tail_expr(make, block, make.expr_unit());
1901 map_tail_expr(make, block, |tail_expr| {
1902 let constructor = match kind {
1903 TryKind::Option => "Some",
1904 TryKind::Result { .. } => "Ok",
1905 };
1906 let func = make.expr_path(make.ident_path(constructor));
1907 let args = make.arg_list(iter::once(tail_expr));
1908 make.expr_call(func, args).into()
1909 })
1910 }
1911 FlowHandler::If { .. } => {
1912 let controlflow_continue = make
1913 .expr_call(
1914 make.expr_path(make.path_from_text("ControlFlow::Continue")),
1915 make.arg_list([make.expr_unit()]),
1916 )
1917 .into();
1918 with_tail_expr(make, block, controlflow_continue)
1919 }
1920 FlowHandler::IfOption { .. } => {
1921 let none = make.expr_path(make.ident_path("None"));
1922 with_tail_expr(make, block, none)
1923 }
1924 FlowHandler::MatchOption { .. } => map_tail_expr(make, block, |tail_expr| {
1925 let some = make.expr_path(make.ident_path("Some"));
1926 let args = make.arg_list(iter::once(tail_expr));
1927 make.expr_call(some, args).into()
1928 }),
1929 FlowHandler::MatchResult { .. } => map_tail_expr(make, block, |tail_expr| {
1930 let ok = make.expr_path(make.ident_path("Ok"));
1931 let args = make.arg_list(iter::once(tail_expr));
1932 make.expr_call(ok, args).into()
1933 }),
1934 }
1935}
1936
1937fn map_tail_expr(
1938 make: &SyntaxFactory,
1939 block: ast::BlockExpr,
1940 f: impl FnOnce(ast::Expr) -> ast::Expr,
1941) -> ast::BlockExpr {
1942 let tail_expr = match block.tail_expr() {
1943 Some(tail_expr) => tail_expr,
1944 None => return block,
1945 };
1946 make.block_expr(block.statements(), Some(f(tail_expr)))
1947}
1948
1949fn with_default_tail_expr(
1950 make: &SyntaxFactory,
1951 block: ast::BlockExpr,
1952 tail_expr: ast::Expr,
1953) -> ast::BlockExpr {
1954 match block.tail_expr() {
1955 Some(_) => block,
1956 None => make.block_expr(block.statements(), Some(tail_expr)),
1957 }
1958}
1959
1960fn with_tail_expr(
1961 make: &SyntaxFactory,
1962 block: ast::BlockExpr,
1963 tail_expr: ast::Expr,
1964) -> ast::BlockExpr {
1965 let stmt_tail_opt: Option<ast::Stmt> =
1966 block.tail_expr().map(|expr| make.expr_stmt(expr).into());
1967
1968 let mut elements: Vec<SyntaxElement> = vec![];
1969
1970 block.statements().for_each(|stmt| {
1971 elements.push(syntax::NodeOrToken::Node(stmt.syntax().clone()));
1972 });
1973
1974 if let Some(stmt_list) = block.stmt_list() {
1975 stmt_list.syntax().children_with_tokens().for_each(|node_or_token| {
1976 if let syntax::NodeOrToken::Token(_) = &node_or_token {
1977 elements.push(node_or_token)
1978 };
1979 });
1980 }
1981
1982 if let Some(stmt_tail) = stmt_tail_opt {
1983 elements.push(syntax::NodeOrToken::Node(stmt_tail.syntax().clone()));
1984 }
1985
1986 make.hacky_block_expr(elements, Some(tail_expr))
1987}
1988
1989fn format_type(ty: &hir::Type<'_>, ctx: &AssistContext<'_, '_>, module: hir::Module) -> String {
1990 ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_owned())
1991}
1992
1993fn is_inherit_attr(attr: &ast::Attr) -> bool {
1994 let Some(name) = attr.simple_name() else { return false };
1995 matches!(name.as_str(), "track_caller" | "cfg")
1996}
1997
1998fn make_ty(
1999 make: &SyntaxFactory,
2000 ty: &hir::Type<'_>,
2001 ctx: &AssistContext<'_, '_>,
2002 module: hir::Module,
2003) -> ast::Type {
2004 let ty_str = format_type(ty, ctx, module);
2005 make.ty(&ty_str)
2006}
2007
2008fn rewrite_body_segment(
2009 ctx: &AssistContext<'_, '_>,
2010 to_this_param: Option<ast::SelfParam>,
2011 params: &[Param<'_>],
2012 handler: &FlowHandler<'_>,
2013 syntax: &SyntaxNode,
2014) -> SyntaxNode {
2015 let to_this_param = to_this_param.and_then(|it| ctx.sema.to_def(&it));
2016 let (param_editor, param_root) = SyntaxEditor::new(syntax.clone());
2017 fix_param_usages(¶m_editor, syntax, ¶m_root, ctx, to_this_param, params);
2018 let syntax = param_editor.finish().new_root().clone();
2019
2020 let (flow_editor, flow_root) = SyntaxEditor::new(syntax);
2021 update_external_control_flow(&flow_editor, &flow_root, handler);
2022 flow_editor.finish().new_root().clone()
2023}
2024
2025fn fix_param_usages(
2027 editor: &SyntaxEditor,
2028 source_syntax: &SyntaxNode,
2029 syntax: &SyntaxNode,
2030 ctx: &AssistContext<'_, '_>,
2031 to_this_param: Option<Local>,
2032 params: &[Param<'_>],
2033) {
2034 let mut usages_for_param: Vec<(&Param<'_>, Vec<ast::Expr>)> = Vec::new();
2035 let mut usages_for_self_param: Vec<ast::Expr> = Vec::new();
2036 let source_range = source_syntax.text_range();
2037 let syntax_offset = source_range.start() - syntax.text_range().start();
2038
2039 let reference_filter = |reference: &FileReference| {
2040 source_range.contains_range(reference.range).then_some(())?;
2041 path_element_of(reference)
2042 };
2043
2044 if let Some(self_param) = to_this_param {
2045 usages_for_self_param = LocalUsages::find_local_usages(ctx, self_param)
2046 .iter()
2047 .filter_map(reference_filter)
2048 .collect();
2049 }
2050 for param in params {
2051 if !param.kind().is_ref() {
2052 continue;
2053 }
2054
2055 let usages = LocalUsages::find_local_usages(ctx, param.var);
2056 let usages = usages.iter().filter_map(reference_filter);
2057
2058 usages_for_param.push((param, usages.unique().collect()));
2059 }
2060
2061 let make = editor.make();
2062 let to_original = |old: &SyntaxNode| {
2063 ctx.sema
2064 .original_range_opt(old)
2065 .map(|orig| crate::utils::cover_edit_range(syntax, orig.range - syntax_offset))
2066 };
2067 let replace = |range, new: &SyntaxNode| {
2068 editor.replace_all(range, vec![new.clone().into()]);
2069 };
2070
2071 for self_usage in usages_for_self_param {
2072 if let Some(original) = to_original(self_usage.syntax()) {
2073 let this_expr = make.expr_path(make.ident_path("this"));
2074 replace(original, this_expr.syntax())
2075 }
2076 }
2077 for (param, usages) in usages_for_param {
2078 for usage in usages {
2079 match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
2080 Some(
2081 ast::Expr::MethodCallExpr(_)
2082 | ast::Expr::FieldExpr(_)
2083 | ast::Expr::IndexExpr(_),
2084 ) => {
2085 }
2087 Some(ast::Expr::RefExpr(node))
2088 if param.kind() == ParamKind::MutRef
2089 && node.mut_token().is_some()
2090 && let Some(original) = to_original(node.syntax()) =>
2091 {
2092 replace(
2093 original,
2094 node.expr().expect("RefExpr::expr() cannot be None").syntax(),
2095 );
2096 }
2097 Some(ast::Expr::RefExpr(node))
2098 if param.kind() == ParamKind::SharedRef
2099 && node.mut_token().is_none()
2100 && let Some(original) = to_original(node.syntax()) =>
2101 {
2102 replace(
2103 original,
2104 node.expr().expect("RefExpr::expr() cannot be None").syntax(),
2105 );
2106 }
2107 Some(_) | None => {
2108 if let Some(original) = to_original(usage.syntax())
2109 && !matches!(usage, ast::Expr::Literal(_))
2111 {
2112 let p = make.expr_prefix(T![*], usage.clone());
2113 replace(original, p.syntax())
2114 }
2115 }
2116 }
2117 }
2118 }
2119}
2120
2121fn update_external_control_flow(
2122 editor: &SyntaxEditor,
2123 syntax: &SyntaxNode,
2124 handler: &FlowHandler<'_>,
2125) {
2126 let mut nested_loop = None;
2127 let mut nested_scope = None;
2128 for event in syntax.preorder() {
2129 match event {
2130 WalkEvent::Enter(e) => match e.kind() {
2131 SyntaxKind::LOOP_EXPR | SyntaxKind::WHILE_EXPR | SyntaxKind::FOR_EXPR
2132 if nested_loop.is_none() =>
2133 {
2134 nested_loop = Some(e.clone());
2135 }
2136 SyntaxKind::FN
2137 | SyntaxKind::CONST
2138 | SyntaxKind::STATIC
2139 | SyntaxKind::IMPL
2140 | SyntaxKind::MODULE
2141 if nested_scope.is_none() =>
2142 {
2143 nested_scope = Some(e.clone());
2144 }
2145 _ => {}
2146 },
2147 WalkEvent::Leave(e) => {
2148 if nested_scope.is_none()
2149 && let Some(expr) = ast::Expr::cast(e.clone())
2150 {
2151 match expr {
2152 ast::Expr::ReturnExpr(return_expr) => {
2153 let expr = return_expr.expr();
2154 if let Some(replacement) =
2155 make_rewritten_flow(handler, expr, editor.make())
2156 {
2157 editor.replace(return_expr.syntax(), replacement.syntax())
2158 }
2159 }
2160 ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => {
2161 let expr = break_expr.expr();
2162 if let Some(replacement) =
2163 make_rewritten_flow(handler, expr, editor.make())
2164 {
2165 editor.replace(break_expr.syntax(), replacement.syntax())
2166 }
2167 }
2168 ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => {
2169 if let Some(replacement) =
2170 make_rewritten_flow(handler, None, editor.make())
2171 {
2172 editor.replace(continue_expr.syntax(), replacement.syntax())
2173 }
2174 }
2175 _ => {
2176 }
2178 }
2179 }
2180
2181 if nested_loop.as_ref() == Some(&e) {
2182 nested_loop = None;
2183 }
2184 if nested_scope.as_ref() == Some(&e) {
2185 nested_scope = None;
2186 }
2187 }
2188 };
2189 }
2190}
2191
2192fn make_rewritten_flow(
2193 handler: &FlowHandler<'_>,
2194 arg_expr: Option<ast::Expr>,
2195 make: &SyntaxFactory,
2196) -> Option<ast::Expr> {
2197 let value = match handler {
2198 FlowHandler::None | FlowHandler::Try { .. } => return None,
2199 FlowHandler::If { .. } => make
2200 .expr_call(
2201 make.expr_path(make.path_from_text("ControlFlow::Break")),
2202 make.arg_list([make.expr_unit()]),
2203 )
2204 .into(),
2205 FlowHandler::IfOption { .. } => {
2206 let expr = arg_expr.unwrap_or_else(|| make.expr_unit());
2207 let args = make.arg_list([expr]);
2208 make.expr_call(make.expr_path(make.ident_path("Some")), args).into()
2209 }
2210 FlowHandler::MatchOption { .. } => make.expr_path(make.ident_path("None")),
2211 FlowHandler::MatchResult { .. } => {
2212 let expr = arg_expr.unwrap_or_else(|| make.expr_unit());
2213 let args = make.arg_list([expr]);
2214 make.expr_call(make.expr_path(make.ident_path("Err")), args).into()
2215 }
2216 };
2217 Some(make.expr_return(Some(value)).into())
2218}
2219
2220#[cfg(test)]
2221mod tests {
2222 use crate::tests::{check_assist, check_assist_not_applicable};
2223
2224 use super::*;
2225
2226 #[test]
2227 fn no_args_from_binary_expr() {
2228 check_assist(
2229 extract_function,
2230 r#"
2231fn foo() {
2232 foo($01 + 1$0);
2233}
2234"#,
2235 r#"
2236fn foo() {
2237 foo(fun_name());
2238}
2239
2240fn $0fun_name() -> i32 {
2241 1 + 1
2242}
2243"#,
2244 );
2245 }
2246
2247 #[test]
2248 fn no_args_from_binary_expr_in_module() {
2249 check_assist(
2250 extract_function,
2251 r#"
2252mod bar {
2253 fn foo() {
2254 foo($01 + 1$0);
2255 }
2256}
2257"#,
2258 r#"
2259mod bar {
2260 fn foo() {
2261 foo(fun_name());
2262 }
2263
2264 fn $0fun_name() -> i32 {
2265 1 + 1
2266 }
2267}
2268"#,
2269 );
2270 }
2271
2272 #[test]
2273 fn no_args_from_binary_expr_indented() {
2274 check_assist(
2275 extract_function,
2276 r#"
2277fn foo() {
2278 $0{ 1 + 1 }$0;
2279}
2280"#,
2281 r#"
2282fn foo() {
2283 fun_name();
2284}
2285
2286fn $0fun_name() -> i32 {
2287 1 + 1
2288}
2289"#,
2290 );
2291 }
2292
2293 #[test]
2294 fn no_args_from_stmt_with_last_expr() {
2295 check_assist(
2296 extract_function,
2297 r#"
2298fn foo() -> i32 {
2299 let k = 1;
2300 $0let m = 1;
2301 m + 1$0
2302}
2303"#,
2304 r#"
2305fn foo() -> i32 {
2306 let k = 1;
2307 fun_name()
2308}
2309
2310fn $0fun_name() -> i32 {
2311 let m = 1;
2312 m + 1
2313}
2314"#,
2315 );
2316 }
2317
2318 #[test]
2319 fn no_args_from_stmt_unit() {
2320 check_assist(
2321 extract_function,
2322 r#"
2323fn foo() {
2324 let k = 3;
2325 $0let m = 1;
2326 let n = m + 1;$0
2327 let g = 5;
2328}
2329"#,
2330 r#"
2331fn foo() {
2332 let k = 3;
2333 fun_name();
2334 let g = 5;
2335}
2336
2337fn $0fun_name() {
2338 let m = 1;
2339 let n = m + 1;
2340}
2341"#,
2342 );
2343 }
2344
2345 #[test]
2346 fn no_args_if() {
2347 check_assist(
2348 extract_function,
2349 r#"
2350fn foo() {
2351 $0if true { }$0
2352}
2353"#,
2354 r#"
2355fn foo() {
2356 fun_name();
2357}
2358
2359fn $0fun_name() {
2360 if true { }
2361}
2362"#,
2363 );
2364 }
2365
2366 #[test]
2367 fn no_args_if_else() {
2368 check_assist(
2369 extract_function,
2370 r#"
2371fn foo() -> i32 {
2372 $0if true { 1 } else { 2 }$0
2373}
2374"#,
2375 r#"
2376fn foo() -> i32 {
2377 fun_name()
2378}
2379
2380fn $0fun_name() -> i32 {
2381 if true { 1 } else { 2 }
2382}
2383"#,
2384 );
2385 }
2386
2387 #[test]
2388 fn no_args_if_let_else() {
2389 check_assist(
2390 extract_function,
2391 r#"
2392fn foo() -> i32 {
2393 $0if let true = false { 1 } else { 2 }$0
2394}
2395"#,
2396 r#"
2397fn foo() -> i32 {
2398 fun_name()
2399}
2400
2401fn $0fun_name() -> i32 {
2402 if let true = false { 1 } else { 2 }
2403}
2404"#,
2405 );
2406 }
2407
2408 #[test]
2409 fn no_args_match() {
2410 check_assist(
2411 extract_function,
2412 r#"
2413fn foo() -> i32 {
2414 $0match true {
2415 true => 1,
2416 false => 2,
2417 }$0
2418}
2419"#,
2420 r#"
2421fn foo() -> i32 {
2422 fun_name()
2423}
2424
2425fn $0fun_name() -> i32 {
2426 match true {
2427 true => 1,
2428 false => 2,
2429 }
2430}
2431"#,
2432 );
2433 }
2434
2435 #[test]
2436 fn no_args_while() {
2437 check_assist(
2438 extract_function,
2439 r#"
2440fn foo() {
2441 $0while true { }$0
2442}
2443"#,
2444 r#"
2445fn foo() {
2446 fun_name();
2447}
2448
2449fn $0fun_name() {
2450 while true { }
2451}
2452"#,
2453 );
2454 }
2455
2456 #[test]
2457 fn no_args_for() {
2458 check_assist(
2459 extract_function,
2460 r#"
2461//- minicore: iterator
2462fn foo() {
2463 $0for v in &[0, 1] { }$0
2464}
2465"#,
2466 r#"
2467fn foo() {
2468 fun_name();
2469}
2470
2471fn $0fun_name() {
2472 for v in &[0, 1] { }
2473}
2474"#,
2475 );
2476 }
2477
2478 #[test]
2479 fn no_args_from_loop_unit() {
2480 check_assist(
2481 extract_function,
2482 r#"
2483fn foo() {
2484 $0loop {
2485 let m = 1;
2486 }$0
2487}
2488"#,
2489 r#"
2490fn foo() {
2491 fun_name()
2492}
2493
2494fn $0fun_name() -> ! {
2495 loop {
2496 let m = 1;
2497 }
2498}
2499"#,
2500 );
2501 }
2502
2503 #[test]
2504 fn no_args_from_loop_with_return() {
2505 check_assist(
2506 extract_function,
2507 r#"
2508fn foo() {
2509 let v = $0loop {
2510 let m = 1;
2511 break m;
2512 }$0;
2513}
2514"#,
2515 r#"
2516fn foo() {
2517 let v = fun_name();
2518}
2519
2520fn $0fun_name() -> i32 {
2521 loop {
2522 let m = 1;
2523 break m;
2524 }
2525}
2526"#,
2527 );
2528 }
2529
2530 #[test]
2531 fn no_args_from_match() {
2532 check_assist(
2533 extract_function,
2534 r#"
2535fn foo() {
2536 let v: i32 = $0match Some(1) {
2537 Some(x) => x,
2538 None => 0,
2539 }$0;
2540}
2541"#,
2542 r#"
2543fn foo() {
2544 let v: i32 = fun_name();
2545}
2546
2547fn $0fun_name() -> i32 {
2548 match Some(1) {
2549 Some(x) => x,
2550 None => 0,
2551 }
2552}
2553"#,
2554 );
2555 }
2556
2557 #[test]
2558 fn extract_partial_block_single_line() {
2559 check_assist(
2560 extract_function,
2561 r#"
2562fn foo() {
2563 let n = 1;
2564 let mut v = $0n * n;$0
2565 v += 1;
2566}
2567"#,
2568 r#"
2569fn foo() {
2570 let n = 1;
2571 let mut v = fun_name(n);
2572 v += 1;
2573}
2574
2575fn $0fun_name(n: i32) -> i32 {
2576 let mut v = n * n;
2577 v
2578}
2579"#,
2580 );
2581 }
2582
2583 #[test]
2584 fn extract_partial_block() {
2585 check_assist(
2586 extract_function,
2587 r#"
2588fn foo() {
2589 let m = 2;
2590 let n = 1;
2591 let mut v = m $0* n;
2592 let mut w = 3;$0
2593 v += 1;
2594 w += 1;
2595}
2596"#,
2597 r#"
2598fn foo() {
2599 let m = 2;
2600 let n = 1;
2601 let (mut v, mut w) = fun_name(m, n);
2602 v += 1;
2603 w += 1;
2604}
2605
2606fn $0fun_name(m: i32, n: i32) -> (i32, i32) {
2607 let mut v = m * n;
2608 let mut w = 3;
2609 (v, w)
2610}
2611"#,
2612 );
2613 }
2614
2615 #[test]
2616 fn argument_form_expr() {
2617 check_assist(
2618 extract_function,
2619 r#"
2620fn foo() -> u32 {
2621 let n = 2;
2622 $0n+2$0
2623}
2624"#,
2625 r#"
2626fn foo() -> u32 {
2627 let n = 2;
2628 fun_name(n)
2629}
2630
2631fn $0fun_name(n: u32) -> u32 {
2632 n+2
2633}
2634"#,
2635 )
2636 }
2637
2638 #[test]
2639 fn argument_used_twice_form_expr() {
2640 check_assist(
2641 extract_function,
2642 r#"
2643fn foo() -> u32 {
2644 let n = 2;
2645 $0n+n$0
2646}
2647"#,
2648 r#"
2649fn foo() -> u32 {
2650 let n = 2;
2651 fun_name(n)
2652}
2653
2654fn $0fun_name(n: u32) -> u32 {
2655 n+n
2656}
2657"#,
2658 )
2659 }
2660
2661 #[test]
2662 fn two_arguments_form_expr() {
2663 check_assist(
2664 extract_function,
2665 r#"
2666fn foo() -> u32 {
2667 let n = 2;
2668 let m = 3;
2669 $0n+n*m$0
2670}
2671"#,
2672 r#"
2673fn foo() -> u32 {
2674 let n = 2;
2675 let m = 3;
2676 fun_name(n, m)
2677}
2678
2679fn $0fun_name(n: u32, m: u32) -> u32 {
2680 n+n*m
2681}
2682"#,
2683 )
2684 }
2685
2686 #[test]
2687 fn argument_and_locals() {
2688 check_assist(
2689 extract_function,
2690 r#"
2691fn foo() -> u32 {
2692 let n = 2;
2693 $0let m = 1;
2694 n + m$0
2695}
2696"#,
2697 r#"
2698fn foo() -> u32 {
2699 let n = 2;
2700 fun_name(n)
2701}
2702
2703fn $0fun_name(n: u32) -> u32 {
2704 let m = 1;
2705 n + m
2706}
2707"#,
2708 )
2709 }
2710
2711 #[test]
2712 fn in_comment_is_not_applicable() {
2713 cov_mark::check!(extract_function_in_comment_is_not_applicable);
2714 check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }");
2715 }
2716
2717 #[test]
2718 fn empty_selection_is_not_applicable() {
2719 cov_mark::check!(extract_function_empty_selection_is_not_applicable);
2720 check_assist_not_applicable(
2721 extract_function,
2722 r#"
2723fn main() {
2724 $0
2725
2726 $0
2727}"#,
2728 );
2729 }
2730
2731 #[test]
2732 fn part_of_expr_stmt() {
2733 check_assist(
2734 extract_function,
2735 r#"
2736fn foo() {
2737 $01$0 + 1;
2738}
2739"#,
2740 r#"
2741fn foo() {
2742 fun_name() + 1;
2743}
2744
2745fn $0fun_name() -> i32 {
2746 1
2747}
2748"#,
2749 );
2750 }
2751
2752 #[test]
2753 fn function_expr() {
2754 check_assist(
2755 extract_function,
2756 r#"
2757fn foo() {
2758 $0bar(1 + 1)$0
2759}
2760"#,
2761 r#"
2762fn foo() {
2763 fun_name();
2764}
2765
2766fn $0fun_name() {
2767 bar(1 + 1)
2768}
2769"#,
2770 )
2771 }
2772
2773 #[test]
2774 fn extract_from_nested() {
2775 check_assist(
2776 extract_function,
2777 r#"
2778fn main() {
2779 let x = true;
2780 let tuple = match x {
2781 true => ($02 + 2$0, true)
2782 _ => (0, false)
2783 };
2784}
2785"#,
2786 r#"
2787fn main() {
2788 let x = true;
2789 let tuple = match x {
2790 true => (fun_name(), true)
2791 _ => (0, false)
2792 };
2793}
2794
2795fn $0fun_name() -> i32 {
2796 2 + 2
2797}
2798"#,
2799 );
2800 }
2801
2802 #[test]
2803 fn param_from_closure() {
2804 check_assist(
2805 extract_function,
2806 r#"
2807fn main() {
2808 let lambda = |x: u32| $0x * 2$0;
2809}
2810"#,
2811 r#"
2812fn main() {
2813 let lambda = |x: u32| fun_name(x);
2814}
2815
2816fn $0fun_name(x: u32) -> u32 {
2817 x * 2
2818}
2819"#,
2820 );
2821 }
2822
2823 #[test]
2824 fn extract_return_stmt() {
2825 check_assist(
2826 extract_function,
2827 r#"
2828fn foo() -> u32 {
2829 $0return 2 + 2$0;
2830}
2831"#,
2832 r#"
2833fn foo() -> u32 {
2834 return fun_name();
2835}
2836
2837fn $0fun_name() -> u32 {
2838 2 + 2
2839}
2840"#,
2841 );
2842 }
2843
2844 #[test]
2845 fn does_not_add_extra_whitespace() {
2846 check_assist(
2847 extract_function,
2848 r#"
2849fn foo() -> u32 {
2850
2851
2852 $0return 2 + 2$0;
2853}
2854"#,
2855 r#"
2856fn foo() -> u32 {
2857
2858
2859 return fun_name();
2860}
2861
2862fn $0fun_name() -> u32 {
2863 2 + 2
2864}
2865"#,
2866 );
2867 }
2868
2869 #[test]
2870 fn break_stmt() {
2871 check_assist(
2872 extract_function,
2873 r#"
2874fn main() {
2875 let result = loop {
2876 $0break 2 + 2$0;
2877 };
2878}
2879"#,
2880 r#"
2881fn main() {
2882 let result = loop {
2883 break fun_name();
2884 };
2885}
2886
2887fn $0fun_name() -> i32 {
2888 2 + 2
2889}
2890"#,
2891 );
2892 }
2893
2894 #[test]
2895 fn extract_cast() {
2896 check_assist(
2897 extract_function,
2898 r#"
2899fn main() {
2900 let v = $00f32 as u32$0;
2901}
2902"#,
2903 r#"
2904fn main() {
2905 let v = fun_name();
2906}
2907
2908fn $0fun_name() -> u32 {
2909 0f32 as u32
2910}
2911"#,
2912 );
2913 }
2914
2915 #[test]
2916 fn return_not_applicable() {
2917 check_assist_not_applicable(extract_function, r"fn foo() { $0return$0; } ");
2918 }
2919
2920 #[test]
2921 fn method_to_freestanding() {
2922 check_assist(
2923 extract_function,
2924 r#"
2925struct S;
2926
2927impl S {
2928 fn foo(&self) -> i32 {
2929 $01+1$0
2930 }
2931}
2932"#,
2933 r#"
2934struct S;
2935
2936impl S {
2937 fn foo(&self) -> i32 {
2938 fun_name()
2939 }
2940}
2941
2942fn $0fun_name() -> i32 {
2943 1+1
2944}
2945"#,
2946 );
2947 }
2948
2949 #[test]
2950 fn method_with_reference() {
2951 check_assist(
2952 extract_function,
2953 r#"
2954struct S { f: i32 };
2955
2956impl S {
2957 fn foo(&self) -> i32 {
2958 $0self.f+self.f$0
2959 }
2960}
2961"#,
2962 r#"
2963struct S { f: i32 };
2964
2965impl S {
2966 fn foo(&self) -> i32 {
2967 self.fun_name()
2968 }
2969
2970 fn $0fun_name(&self) -> i32 {
2971 self.f+self.f
2972 }
2973}
2974"#,
2975 );
2976 }
2977
2978 #[test]
2979 fn method_with_mut() {
2980 check_assist(
2981 extract_function,
2982 r#"
2983struct S { f: i32 };
2984
2985impl S {
2986 fn foo(&mut self) {
2987 $0self.f += 1;$0
2988 }
2989}
2990"#,
2991 r#"
2992struct S { f: i32 };
2993
2994impl S {
2995 fn foo(&mut self) {
2996 self.fun_name();
2997 }
2998
2999 fn $0fun_name(&mut self) {
3000 self.f += 1;
3001 }
3002}
3003"#,
3004 );
3005 }
3006
3007 #[test]
3008 fn method_in_trait() {
3009 check_assist(
3010 extract_function,
3011 r#"
3012trait Foo {
3013 fn f(&self) -> i32;
3014
3015 fn foo(&self) -> i32 {
3016 $0self.f()+self.f()$0
3017 }
3018}
3019"#,
3020 r#"
3021trait Foo {
3022 fn f(&self) -> i32;
3023
3024 fn foo(&self) -> i32 {
3025 fun_name(self)
3026 }
3027}
3028
3029fn $0fun_name(this: &impl Foo) -> i32 {
3030 this.f()+this.f()
3031}
3032"#,
3033 );
3034 }
3035
3036 #[test]
3037 fn variable_defined_inside_and_used_after_no_ret() {
3038 check_assist(
3039 extract_function,
3040 r#"
3041fn foo() {
3042 let n = 1;
3043 $0let k = n * n;$0
3044 let m = k + 1;
3045}
3046"#,
3047 r#"
3048fn foo() {
3049 let n = 1;
3050 let k = fun_name(n);
3051 let m = k + 1;
3052}
3053
3054fn $0fun_name(n: i32) -> i32 {
3055 let k = n * n;
3056 k
3057}
3058"#,
3059 );
3060 }
3061
3062 #[test]
3063 fn variable_defined_inside_and_used_after_mutably_no_ret() {
3064 check_assist(
3065 extract_function,
3066 r#"
3067fn foo() {
3068 let n = 1;
3069 $0let mut k = n * n;$0
3070 k += 1;
3071}
3072"#,
3073 r#"
3074fn foo() {
3075 let n = 1;
3076 let mut k = fun_name(n);
3077 k += 1;
3078}
3079
3080fn $0fun_name(n: i32) -> i32 {
3081 let mut k = n * n;
3082 k
3083}
3084"#,
3085 );
3086 }
3087
3088 #[test]
3089 fn two_variables_defined_inside_and_used_after_no_ret() {
3090 check_assist(
3091 extract_function,
3092 r#"
3093fn foo() {
3094 let n = 1;
3095 $0let k = n * n;
3096 let m = k + 2;$0
3097 let h = k + m;
3098}
3099"#,
3100 r#"
3101fn foo() {
3102 let n = 1;
3103 let (k, m) = fun_name(n);
3104 let h = k + m;
3105}
3106
3107fn $0fun_name(n: i32) -> (i32, i32) {
3108 let k = n * n;
3109 let m = k + 2;
3110 (k, m)
3111}
3112"#,
3113 );
3114 }
3115
3116 #[test]
3117 fn multi_variables_defined_inside_and_used_after_mutably_no_ret() {
3118 check_assist(
3119 extract_function,
3120 r#"
3121fn foo() {
3122 let n = 1;
3123 $0let mut k = n * n;
3124 let mut m = k + 2;
3125 let mut o = m + 3;
3126 o += 1;$0
3127 k += o;
3128 m = 1;
3129}
3130"#,
3131 r#"
3132fn foo() {
3133 let n = 1;
3134 let (mut k, mut m, o) = fun_name(n);
3135 k += o;
3136 m = 1;
3137}
3138
3139fn $0fun_name(n: i32) -> (i32, i32, i32) {
3140 let mut k = n * n;
3141 let mut m = k + 2;
3142 let mut o = m + 3;
3143 o += 1;
3144 (k, m, o)
3145}
3146"#,
3147 );
3148 }
3149
3150 #[test]
3151 fn nontrivial_patterns_define_variables() {
3152 check_assist(
3153 extract_function,
3154 r#"
3155struct Counter(i32);
3156fn foo() {
3157 $0let Counter(n) = Counter(0);$0
3158 let m = n;
3159}
3160"#,
3161 r#"
3162struct Counter(i32);
3163fn foo() {
3164 let n = fun_name();
3165 let m = n;
3166}
3167
3168fn $0fun_name() -> i32 {
3169 let Counter(n) = Counter(0);
3170 n
3171}
3172"#,
3173 );
3174 }
3175
3176 #[test]
3177 fn struct_with_two_fields_pattern_define_variables() {
3178 check_assist(
3179 extract_function,
3180 r#"
3181struct Counter { n: i32, m: i32 };
3182fn foo() {
3183 $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0
3184 let h = n + k;
3185}
3186"#,
3187 r#"
3188struct Counter { n: i32, m: i32 };
3189fn foo() {
3190 let (n, k) = fun_name();
3191 let h = n + k;
3192}
3193
3194fn $0fun_name() -> (i32, i32) {
3195 let Counter { n, m: k } = Counter { n: 1, m: 2 };
3196 (n, k)
3197}
3198"#,
3199 );
3200 }
3201
3202 #[test]
3203 fn mut_var_from_outer_scope() {
3204 check_assist(
3205 extract_function,
3206 r#"
3207fn foo() {
3208 let mut n = 1;
3209 $0n += 1;$0
3210 let m = n + 1;
3211}
3212"#,
3213 r#"
3214fn foo() {
3215 let mut n = 1;
3216 fun_name(&mut n);
3217 let m = n + 1;
3218}
3219
3220fn $0fun_name(n: &mut i32) {
3221 *n += 1;
3222}
3223"#,
3224 );
3225 }
3226
3227 #[test]
3228 fn mut_index_from_outer_scope() {
3229 check_assist(
3230 extract_function,
3231 r#"
3232//- minicore: index
3233fn foo() {
3234 let mut arr = [1i32];
3235 $0arr[0] = 3;$0
3236 let _ = arr;
3237}
3238"#,
3239 r#"
3240fn foo() {
3241 let mut arr = [1i32];
3242 fun_name(&mut arr);
3243 let _ = arr;
3244}
3245
3246fn $0fun_name(arr: &mut [i32; 1]) {
3247 arr[0] = 3;
3248}
3249"#,
3250 );
3251 }
3252
3253 #[test]
3254 fn mut_field_from_outer_scope() {
3255 check_assist(
3256 extract_function,
3257 r#"
3258struct C { n: i32 }
3259fn foo() {
3260 let mut c = C { n: 0 };
3261 $0c.n += 1;$0
3262 let m = c.n + 1;
3263}
3264"#,
3265 r#"
3266struct C { n: i32 }
3267fn foo() {
3268 let mut c = C { n: 0 };
3269 fun_name(&mut c);
3270 let m = c.n + 1;
3271}
3272
3273fn $0fun_name(c: &mut C) {
3274 c.n += 1;
3275}
3276"#,
3277 );
3278 }
3279
3280 #[test]
3281 fn mut_nested_field_from_outer_scope() {
3282 check_assist(
3283 extract_function,
3284 r#"
3285struct P { n: i32}
3286struct C { p: P }
3287fn foo() {
3288 let mut c = C { p: P { n: 0 } };
3289 let mut v = C { p: P { n: 0 } };
3290 let u = C { p: P { n: 0 } };
3291 $0c.p.n += u.p.n;
3292 let r = &mut v.p.n;$0
3293 let m = c.p.n + v.p.n + u.p.n;
3294}
3295"#,
3296 r#"
3297struct P { n: i32}
3298struct C { p: P }
3299fn foo() {
3300 let mut c = C { p: P { n: 0 } };
3301 let mut v = C { p: P { n: 0 } };
3302 let u = C { p: P { n: 0 } };
3303 fun_name(&mut c, &mut v, &u);
3304 let m = c.p.n + v.p.n + u.p.n;
3305}
3306
3307fn $0fun_name(c: &mut C, v: &mut C, u: &C) {
3308 c.p.n += u.p.n;
3309 let r = &mut v.p.n;
3310}
3311"#,
3312 );
3313 }
3314
3315 #[test]
3316 fn mut_param_many_usages_stmt() {
3317 check_assist(
3318 extract_function,
3319 r#"
3320fn bar(k: i32) {}
3321trait I: Copy {
3322 fn succ(&self) -> Self;
3323 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
3324}
3325impl I for i32 {
3326 fn succ(&self) -> Self { *self + 1 }
3327}
3328fn foo() {
3329 let mut n = 1;
3330 $0n += n;
3331 bar(n);
3332 bar(n+1);
3333 bar(n*n);
3334 bar(&n);
3335 n.inc();
3336 let v = &mut n;
3337 *v = v.succ();
3338 n.succ();$0
3339 let m = n + 1;
3340}
3341"#,
3342 r#"
3343fn bar(k: i32) {}
3344trait I: Copy {
3345 fn succ(&self) -> Self;
3346 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
3347}
3348impl I for i32 {
3349 fn succ(&self) -> Self { *self + 1 }
3350}
3351fn foo() {
3352 let mut n = 1;
3353 fun_name(&mut n);
3354 let m = n + 1;
3355}
3356
3357fn $0fun_name(n: &mut i32) {
3358 *n += *n;
3359 bar(*n);
3360 bar(*n+1);
3361 bar(*n**n);
3362 bar(&*n);
3363 n.inc();
3364 let v = n;
3365 *v = v.succ();
3366 n.succ();
3367}
3368"#,
3369 );
3370 }
3371
3372 #[test]
3373 fn mut_param_many_usages_expr() {
3374 check_assist(
3375 extract_function,
3376 r#"
3377fn bar(k: i32) {}
3378trait I: Copy {
3379 fn succ(&self) -> Self;
3380 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
3381}
3382impl I for i32 {
3383 fn succ(&self) -> Self { *self + 1 }
3384}
3385fn foo() {
3386 let mut n = 1;
3387 $0{
3388 n += n;
3389 bar(n);
3390 bar(n+1);
3391 bar(n*n);
3392 bar(&n);
3393 n.inc();
3394 let v = &mut n;
3395 *v = v.succ();
3396 n.succ();
3397 }$0
3398 let m = n + 1;
3399}
3400"#,
3401 r#"
3402fn bar(k: i32) {}
3403trait I: Copy {
3404 fn succ(&self) -> Self;
3405 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
3406}
3407impl I for i32 {
3408 fn succ(&self) -> Self { *self + 1 }
3409}
3410fn foo() {
3411 let mut n = 1;
3412 fun_name(&mut n);
3413 let m = n + 1;
3414}
3415
3416fn $0fun_name(n: &mut i32) {
3417 *n += *n;
3418 bar(*n);
3419 bar(*n+1);
3420 bar(*n**n);
3421 bar(&*n);
3422 n.inc();
3423 let v = n;
3424 *v = v.succ();
3425 n.succ();
3426}
3427"#,
3428 );
3429 }
3430
3431 #[test]
3432 fn mut_param_by_value() {
3433 check_assist(
3434 extract_function,
3435 r#"
3436fn foo() {
3437 let mut n = 1;
3438 $0n += 1;$0
3439}
3440"#,
3441 r"
3442fn foo() {
3443 let mut n = 1;
3444 fun_name(n);
3445}
3446
3447fn $0fun_name(mut n: i32) {
3448 n += 1;
3449}
3450",
3451 );
3452 }
3453
3454 #[test]
3455 fn mut_param_because_of_mut_ref() {
3456 check_assist(
3457 extract_function,
3458 r#"
3459fn foo() {
3460 let mut n = 1;
3461 $0let v = &mut n;
3462 *v += 1;$0
3463 let k = n;
3464}
3465"#,
3466 r#"
3467fn foo() {
3468 let mut n = 1;
3469 fun_name(&mut n);
3470 let k = n;
3471}
3472
3473fn $0fun_name(n: &mut i32) {
3474 let v = n;
3475 *v += 1;
3476}
3477"#,
3478 );
3479 }
3480
3481 #[test]
3482 fn mut_param_because_of_mut_ref_in_macro() {
3483 check_assist(
3484 extract_function,
3485 r#"
3486macro_rules! refmut { ($e:expr) => { &mut $e }; }
3487fn foo() {
3488 let mut n = 1;
3489 $0let v = refmut!(n);
3490 *v += 1;$0
3491 let k = n;
3492}
3493"#,
3494 r#"
3495macro_rules! refmut { ($e:expr) => { &mut $e }; }
3496fn foo() {
3497 let mut n = 1;
3498 fun_name(&mut n);
3499 let k = n;
3500}
3501
3502fn $0fun_name(n: &mut i32) {
3503 let v = refmut!(*n);
3504 *v += 1;
3505}
3506"#,
3507 );
3508
3509 check_assist(
3510 extract_function,
3511 r#"
3512macro_rules! id { ($e:expr) => { $e }; }
3513fn foo() {
3514 let mut n = 1;
3515 $0let v = id!(&mut n);
3516 *v += 1;$0
3517 let k = n;
3518}
3519"#,
3520 r#"
3521macro_rules! id { ($e:expr) => { $e }; }
3522fn foo() {
3523 let mut n = 1;
3524 fun_name(&mut n);
3525 let k = n;
3526}
3527
3528fn $0fun_name(n: &mut i32) {
3529 let v = id!(n);
3530 *v += 1;
3531}
3532"#,
3533 );
3534 }
3535
3536 #[test]
3537 fn mut_param_by_value_because_of_mut_ref() {
3538 check_assist(
3539 extract_function,
3540 r"
3541fn foo() {
3542 let mut n = 1;
3543 $0let v = &mut n;
3544 *v += 1;$0
3545}
3546",
3547 r#"
3548fn foo() {
3549 let mut n = 1;
3550 fun_name(n);
3551}
3552
3553fn $0fun_name(mut n: i32) {
3554 let v = &mut n;
3555 *v += 1;
3556}
3557"#,
3558 );
3559 }
3560
3561 #[test]
3562 fn mut_method_call() {
3563 check_assist(
3564 extract_function,
3565 r#"
3566trait I {
3567 fn inc(&mut self);
3568}
3569impl I for i32 {
3570 fn inc(&mut self) { *self += 1 }
3571}
3572fn foo() {
3573 let mut n = 1;
3574 $0n.inc();$0
3575}
3576"#,
3577 r#"
3578trait I {
3579 fn inc(&mut self);
3580}
3581impl I for i32 {
3582 fn inc(&mut self) { *self += 1 }
3583}
3584fn foo() {
3585 let mut n = 1;
3586 fun_name(n);
3587}
3588
3589fn $0fun_name(mut n: i32) {
3590 n.inc();
3591}
3592"#,
3593 );
3594 }
3595
3596 #[test]
3597 fn shared_method_call() {
3598 check_assist(
3599 extract_function,
3600 r#"
3601trait I {
3602 fn succ(&self);
3603}
3604impl I for i32 {
3605 fn succ(&self) { *self + 1 }
3606}
3607fn foo() {
3608 let mut n = 1;
3609 $0n.succ();$0
3610}
3611"#,
3612 r"
3613trait I {
3614 fn succ(&self);
3615}
3616impl I for i32 {
3617 fn succ(&self) { *self + 1 }
3618}
3619fn foo() {
3620 let mut n = 1;
3621 fun_name(n);
3622}
3623
3624fn $0fun_name(n: i32) {
3625 n.succ();
3626}
3627",
3628 );
3629 }
3630
3631 #[test]
3632 fn mut_method_call_with_other_receiver() {
3633 check_assist(
3634 extract_function,
3635 r#"
3636trait I {
3637 fn inc(&mut self, n: i32);
3638}
3639impl I for i32 {
3640 fn inc(&mut self, n: i32) { *self += n }
3641}
3642fn foo() {
3643 let mut n = 1;
3644 $0let mut m = 2;
3645 m.inc(n);$0
3646}
3647"#,
3648 r"
3649trait I {
3650 fn inc(&mut self, n: i32);
3651}
3652impl I for i32 {
3653 fn inc(&mut self, n: i32) { *self += n }
3654}
3655fn foo() {
3656 let mut n = 1;
3657 fun_name(n);
3658}
3659
3660fn $0fun_name(n: i32) {
3661 let mut m = 2;
3662 m.inc(n);
3663}
3664",
3665 );
3666 }
3667
3668 #[test]
3669 fn non_copy_without_usages_after() {
3670 check_assist(
3671 extract_function,
3672 r#"
3673struct Counter(i32);
3674fn foo() {
3675 let c = Counter(0);
3676 $0let n = c.0;$0
3677}
3678"#,
3679 r"
3680struct Counter(i32);
3681fn foo() {
3682 let c = Counter(0);
3683 fun_name(c);
3684}
3685
3686fn $0fun_name(c: Counter) {
3687 let n = c.0;
3688}
3689",
3690 );
3691 }
3692
3693 #[test]
3694 fn non_copy_used_after() {
3695 check_assist(
3696 extract_function,
3697 r"
3698struct Counter(i32);
3699fn foo() {
3700 let c = Counter(0);
3701 $0let n = c.0;$0
3702 let m = c.0;
3703}
3704",
3705 r#"
3706struct Counter(i32);
3707fn foo() {
3708 let c = Counter(0);
3709 fun_name(&c);
3710 let m = c.0;
3711}
3712
3713fn $0fun_name(c: &Counter) {
3714 let n = c.0;
3715}
3716"#,
3717 );
3718 }
3719
3720 #[test]
3721 fn copy_used_after() {
3722 check_assist(
3723 extract_function,
3724 r#"
3725//- minicore: copy
3726fn foo() {
3727 let n = 0;
3728 $0let m = n;$0
3729 let k = n;
3730}
3731"#,
3732 r#"
3733fn foo() {
3734 let n = 0;
3735 fun_name(n);
3736 let k = n;
3737}
3738
3739fn $0fun_name(n: i32) {
3740 let m = n;
3741}
3742"#,
3743 )
3744 }
3745
3746 #[test]
3747 fn copy_custom_used_after() {
3748 check_assist(
3749 extract_function,
3750 r#"
3751//- minicore: copy, derive
3752#[derive(Clone, Copy)]
3753struct Counter(i32);
3754fn foo() {
3755 let c = Counter(0);
3756 $0let n = c.0;$0
3757 let m = c.0;
3758}
3759"#,
3760 r#"
3761#[derive(Clone, Copy)]
3762struct Counter(i32);
3763fn foo() {
3764 let c = Counter(0);
3765 fun_name(c);
3766 let m = c.0;
3767}
3768
3769fn $0fun_name(c: Counter) {
3770 let n = c.0;
3771}
3772"#,
3773 );
3774 }
3775
3776 #[test]
3777 fn indented_stmts() {
3778 check_assist(
3779 extract_function,
3780 r#"
3781fn foo() {
3782 if true {
3783 loop {
3784 $0let n = 1;
3785 let m = 2;$0
3786 }
3787 }
3788}
3789"#,
3790 r#"
3791fn foo() {
3792 if true {
3793 loop {
3794 fun_name();
3795 }
3796 }
3797}
3798
3799fn $0fun_name() {
3800 let n = 1;
3801 let m = 2;
3802}
3803"#,
3804 );
3805 }
3806
3807 #[test]
3808 fn indented_stmts_inside_mod() {
3809 check_assist(
3810 extract_function,
3811 r#"
3812mod bar {
3813 fn foo() {
3814 if true {
3815 loop {
3816 $0let n = 1;
3817 let m = 2;$0
3818 }
3819 }
3820 }
3821}
3822"#,
3823 r#"
3824mod bar {
3825 fn foo() {
3826 if true {
3827 loop {
3828 fun_name();
3829 }
3830 }
3831 }
3832
3833 fn $0fun_name() {
3834 let n = 1;
3835 let m = 2;
3836 }
3837}
3838"#,
3839 );
3840 }
3841
3842 #[test]
3843 fn break_loop() {
3844 check_assist(
3845 extract_function,
3846 r#"
3847//- minicore: option
3848fn foo() {
3849 loop {
3850 let n = 1;
3851 $0let m = n + 1;
3852 break;
3853 let k = 2;$0
3854 let h = 1 + k;
3855 }
3856}
3857"#,
3858 r#"
3859fn foo() {
3860 loop {
3861 let n = 1;
3862 let k = match fun_name(n) {
3863 Some(value) => value,
3864 None => break,
3865 };
3866 let h = 1 + k;
3867 }
3868}
3869
3870fn $0fun_name(n: i32) -> Option<i32> {
3871 let m = n + 1;
3872 return None;
3873 let k = 2;
3874 Some(k)
3875}
3876"#,
3877 );
3878 }
3879
3880 #[test]
3881 fn return_to_parent() {
3882 check_assist(
3883 extract_function,
3884 r#"
3885//- minicore: copy, result
3886fn foo() -> i64 {
3887 let n = 1;
3888 $0let m = n + 1;
3889 return 1;
3890 let k = 2;$0
3891 (n + k) as i64
3892}
3893"#,
3894 r#"
3895fn foo() -> i64 {
3896 let n = 1;
3897 let k = match fun_name(n) {
3898 Ok(value) => value,
3899 Err(value) => return value,
3900 };
3901 (n + k) as i64
3902}
3903
3904fn $0fun_name(n: i32) -> Result<i32, i64> {
3905 let m = n + 1;
3906 return Err(1);
3907 let k = 2;
3908 Ok(k)
3909}
3910"#,
3911 );
3912 }
3913
3914 #[test]
3915 fn break_and_continue() {
3916 cov_mark::check!(external_control_flow_break_and_continue);
3917 check_assist_not_applicable(
3918 extract_function,
3919 r#"
3920fn foo() {
3921 loop {
3922 let n = 1;
3923 $0let m = n + 1;
3924 break;
3925 let k = 2;
3926 continue;
3927 let k = k + 1;$0
3928 let r = n + k;
3929 }
3930}
3931"#,
3932 );
3933 }
3934
3935 #[test]
3936 fn return_and_break() {
3937 cov_mark::check!(external_control_flow_return_and_bc);
3938 check_assist_not_applicable(
3939 extract_function,
3940 r#"
3941fn foo() {
3942 loop {
3943 let n = 1;
3944 $0let m = n + 1;
3945 break;
3946 let k = 2;
3947 return;
3948 let k = k + 1;$0
3949 let r = n + k;
3950 }
3951}
3952"#,
3953 );
3954 }
3955
3956 #[test]
3957 fn break_loop_with_if() {
3958 check_assist(
3959 extract_function,
3960 r#"
3961//- minicore: try
3962fn foo() {
3963 loop {
3964 let mut n = 1;
3965 $0let m = n + 1;
3966 break;
3967 n += m;$0
3968 let h = 1 + n;
3969 }
3970}
3971"#,
3972 r#"
3973use core::ops::ControlFlow;
3974
3975fn foo() {
3976 loop {
3977 let mut n = 1;
3978 if let ControlFlow::Break(_) = fun_name(&mut n) {
3979 break;
3980 }
3981 let h = 1 + n;
3982 }
3983}
3984
3985fn $0fun_name(n: &mut i32) -> ControlFlow<()> {
3986 let m = *n + 1;
3987 return ControlFlow::Break(());
3988 *n += m;
3989 ControlFlow::Continue(())
3990}
3991"#,
3992 );
3993 }
3994
3995 #[test]
3996 fn break_loop_nested() {
3997 check_assist(
3998 extract_function,
3999 r#"
4000//- minicore: try
4001fn foo() {
4002 loop {
4003 let mut n = 1;
4004 $0let m = n + 1;
4005 if m == 42 {
4006 break;
4007 }$0
4008 let h = 1;
4009 }
4010}
4011"#,
4012 r#"
4013use core::ops::ControlFlow;
4014
4015fn foo() {
4016 loop {
4017 let mut n = 1;
4018 if let ControlFlow::Break(_) = fun_name(n) {
4019 break;
4020 }
4021 let h = 1;
4022 }
4023}
4024
4025fn $0fun_name(n: i32) -> ControlFlow<()> {
4026 let m = n + 1;
4027 if m == 42 {
4028 return ControlFlow::Break(());
4029 }
4030 ControlFlow::Continue(())
4031}
4032"#,
4033 );
4034 }
4035
4036 #[test]
4037 fn break_loop_nested_labeled() {
4038 check_assist(
4039 extract_function,
4040 r#"
4041//- minicore: try
4042fn foo() {
4043 'bar: loop {
4044 loop {
4045 $0break 'bar;$0
4046 }
4047 }
4048}
4049"#,
4050 r#"
4051use core::ops::ControlFlow;
4052
4053fn foo() {
4054 'bar: loop {
4055 loop {
4056 if let ControlFlow::Break(_) = fun_name() {
4057 break 'bar;
4058 }
4059 }
4060 }
4061}
4062
4063fn $0fun_name() -> ControlFlow<()> {
4064 return ControlFlow::Break(());
4065 ControlFlow::Continue(())
4066}
4067"#,
4068 );
4069 }
4070
4071 #[test]
4072 fn continue_loop_nested_labeled() {
4073 check_assist(
4074 extract_function,
4075 r#"
4076//- minicore: try
4077fn foo() {
4078 'bar: loop {
4079 loop {
4080 $0continue 'bar;$0
4081 }
4082 }
4083}
4084"#,
4085 r#"
4086use core::ops::ControlFlow;
4087
4088fn foo() {
4089 'bar: loop {
4090 loop {
4091 if let ControlFlow::Break(_) = fun_name() {
4092 continue 'bar;
4093 }
4094 }
4095 }
4096}
4097
4098fn $0fun_name() -> ControlFlow<()> {
4099 return ControlFlow::Break(());
4100 ControlFlow::Continue(())
4101}
4102"#,
4103 );
4104 }
4105
4106 #[test]
4107 fn return_from_nested_loop() {
4108 check_assist(
4109 extract_function,
4110 r#"
4111fn foo() {
4112 loop {
4113 let n = 1;$0
4114 let k = 1;
4115 loop {
4116 return;
4117 }
4118 let m = k + 1;$0
4119 let h = 1 + m;
4120 }
4121}
4122"#,
4123 r#"
4124fn foo() {
4125 loop {
4126 let n = 1;
4127 let m = match fun_name() {
4128 Some(value) => value,
4129 None => return,
4130 };
4131 let h = 1 + m;
4132 }
4133}
4134
4135fn $0fun_name() -> Option<i32> {
4136 let k = 1;
4137 loop {
4138 return None;
4139 }
4140 let m = k + 1;
4141 Some(m)
4142}
4143"#,
4144 );
4145 }
4146
4147 #[test]
4148 fn break_from_nested_loop() {
4149 check_assist(
4150 extract_function,
4151 r#"
4152fn foo() {
4153 loop {
4154 let n = 1;
4155 $0let k = 1;
4156 loop {
4157 break;
4158 }
4159 let m = k + 1;$0
4160 let h = 1 + m;
4161 }
4162}
4163"#,
4164 r#"
4165fn foo() {
4166 loop {
4167 let n = 1;
4168 let m = fun_name();
4169 let h = 1 + m;
4170 }
4171}
4172
4173fn $0fun_name() -> i32 {
4174 let k = 1;
4175 loop {
4176 break;
4177 }
4178 let m = k + 1;
4179 m
4180}
4181"#,
4182 );
4183 }
4184
4185 #[test]
4186 fn break_from_nested_and_outer_loops() {
4187 check_assist(
4188 extract_function,
4189 r#"
4190fn foo() {
4191 loop {
4192 let n = 1;
4193 $0let k = 1;
4194 loop {
4195 break;
4196 }
4197 if k == 42 {
4198 break;
4199 }
4200 let m = k + 1;$0
4201 let h = 1 + m;
4202 }
4203}
4204"#,
4205 r#"
4206fn foo() {
4207 loop {
4208 let n = 1;
4209 let m = match fun_name() {
4210 Some(value) => value,
4211 None => break,
4212 };
4213 let h = 1 + m;
4214 }
4215}
4216
4217fn $0fun_name() -> Option<i32> {
4218 let k = 1;
4219 loop {
4220 break;
4221 }
4222 if k == 42 {
4223 return None;
4224 }
4225 let m = k + 1;
4226 Some(m)
4227}
4228"#,
4229 );
4230 }
4231
4232 #[test]
4233 fn return_from_nested_fn() {
4234 check_assist(
4235 extract_function,
4236 r#"
4237fn foo() {
4238 loop {
4239 let n = 1;
4240 $0let k = 1;
4241 fn test() {
4242 return;
4243 }
4244 let m = k + 1;$0
4245 let h = 1 + m;
4246 }
4247}
4248"#,
4249 r#"
4250fn foo() {
4251 loop {
4252 let n = 1;
4253 let m = fun_name();
4254 let h = 1 + m;
4255 }
4256}
4257
4258fn $0fun_name() -> i32 {
4259 let k = 1;
4260 fn test() {
4261 return;
4262 }
4263 let m = k + 1;
4264 m
4265}
4266"#,
4267 );
4268 }
4269
4270 #[test]
4271 fn break_with_value() {
4272 check_assist(
4273 extract_function,
4274 r#"
4275fn foo() -> i32 {
4276 loop {
4277 let n = 1;
4278 $0let k = 1;
4279 if k == 42 {
4280 break 3;
4281 }
4282 let m = k + 1;$0
4283 let h = 1;
4284 }
4285}
4286"#,
4287 r#"
4288fn foo() -> i32 {
4289 loop {
4290 let n = 1;
4291 if let Some(value) = fun_name() {
4292 break value;
4293 }
4294 let h = 1;
4295 }
4296}
4297
4298fn $0fun_name() -> Option<i32> {
4299 let k = 1;
4300 if k == 42 {
4301 return Some(3);
4302 }
4303 let m = k + 1;
4304 None
4305}
4306"#,
4307 );
4308 }
4309
4310 #[test]
4311 fn break_with_value_and_label() {
4312 check_assist(
4313 extract_function,
4314 r#"
4315fn foo() -> i32 {
4316 'bar: loop {
4317 let n = 1;
4318 $0let k = 1;
4319 if k == 42 {
4320 break 'bar 4;
4321 }
4322 let m = k + 1;$0
4323 let h = 1;
4324 }
4325}
4326"#,
4327 r#"
4328fn foo() -> i32 {
4329 'bar: loop {
4330 let n = 1;
4331 if let Some(value) = fun_name() {
4332 break 'bar value;
4333 }
4334 let h = 1;
4335 }
4336}
4337
4338fn $0fun_name() -> Option<i32> {
4339 let k = 1;
4340 if k == 42 {
4341 return Some(4);
4342 }
4343 let m = k + 1;
4344 None
4345}
4346"#,
4347 );
4348 }
4349
4350 #[test]
4351 fn break_with_value_and_return() {
4352 check_assist(
4353 extract_function,
4354 r#"
4355fn foo() -> i64 {
4356 loop {
4357 let n = 1;$0
4358 let k = 1;
4359 if k == 42 {
4360 break 3;
4361 }
4362 let m = k + 1;$0
4363 let h = 1 + m;
4364 }
4365}
4366"#,
4367 r#"
4368fn foo() -> i64 {
4369 loop {
4370 let n = 1;
4371 let m = match fun_name() {
4372 Ok(value) => value,
4373 Err(value) => break value,
4374 };
4375 let h = 1 + m;
4376 }
4377}
4378
4379fn $0fun_name() -> Result<i32, i64> {
4380 let k = 1;
4381 if k == 42 {
4382 return Err(3);
4383 }
4384 let m = k + 1;
4385 Ok(m)
4386}
4387"#,
4388 );
4389 }
4390
4391 #[test]
4392 fn try_option() {
4393 check_assist(
4394 extract_function,
4395 r#"
4396//- minicore: option, add, builtin_impls
4397fn bar() -> Option<i32> { None }
4398fn foo() -> Option<()> {
4399 let n = bar()?;
4400 $0let k = foo()?;
4401 let m = k + 1;$0
4402 let h = 1 + m;
4403 Some(())
4404}
4405"#,
4406 r#"
4407fn bar() -> Option<i32> { None }
4408fn foo() -> Option<()> {
4409 let n = bar()?;
4410 let m = fun_name()?;
4411 let h = 1 + m;
4412 Some(())
4413}
4414
4415fn $0fun_name() -> Option<i32> {
4416 let k = foo()?;
4417 let m = k + 1;
4418 Some(m)
4419}
4420"#,
4421 );
4422 }
4423
4424 #[test]
4425 fn try_option_unit() {
4426 check_assist(
4427 extract_function,
4428 r#"
4429//- minicore: option
4430fn foo() -> Option<()> {
4431 let n = 1;
4432 $0let k = foo()?;
4433 let m = k + 1;$0
4434 let h = 1 + n;
4435 Some(())
4436}
4437"#,
4438 r#"
4439fn foo() -> Option<()> {
4440 let n = 1;
4441 fun_name()?;
4442 let h = 1 + n;
4443 Some(())
4444}
4445
4446fn $0fun_name() -> Option<()> {
4447 let k = foo()?;
4448 let m = k + 1;
4449 Some(())
4450}
4451"#,
4452 );
4453 }
4454
4455 #[test]
4456 fn try_result() {
4457 check_assist(
4458 extract_function,
4459 r#"
4460//- minicore: result, add, builtin_impls
4461fn foo() -> Result<(), i64> {
4462 let n = 1;
4463 $0let k = foo()?;
4464 let m = k + 1;$0
4465 let h = 1 + m;
4466 Ok(())
4467}
4468"#,
4469 r#"
4470fn foo() -> Result<(), i64> {
4471 let n = 1;
4472 let m = fun_name()?;
4473 let h = 1 + m;
4474 Ok(())
4475}
4476
4477fn $0fun_name() -> Result<i32, i64> {
4478 let k = foo()?;
4479 let m = k + 1;
4480 Ok(m)
4481}
4482"#,
4483 );
4484 }
4485
4486 #[test]
4487 fn try_option_with_return() {
4488 check_assist(
4489 extract_function,
4490 r#"
4491//- minicore: option, add, builtin_impls
4492fn foo() -> Option<()> {
4493 let n = 1;
4494 $0let k = foo()?;
4495 if k == 42 {
4496 return None;
4497 }
4498 let m = k + 1;$0
4499 let h = 1 + m;
4500 Some(())
4501}
4502"#,
4503 r#"
4504fn foo() -> Option<()> {
4505 let n = 1;
4506 let m = fun_name()?;
4507 let h = 1 + m;
4508 Some(())
4509}
4510
4511fn $0fun_name() -> Option<i32> {
4512 let k = foo()?;
4513 if k == 42 {
4514 return None;
4515 }
4516 let m = k + 1;
4517 Some(m)
4518}
4519"#,
4520 );
4521 }
4522
4523 #[test]
4524 fn try_result_with_return() {
4525 check_assist(
4526 extract_function,
4527 r#"
4528//- minicore: result, add, builtin_impls
4529fn foo() -> Result<(), i64> {
4530 let n = 1;
4531 $0let k = foo()?;
4532 if k == 42 {
4533 return Err(1);
4534 }
4535 let m = k + 1;$0
4536 let h = 1 + m;
4537 Ok(())
4538}
4539"#,
4540 r#"
4541fn foo() -> Result<(), i64> {
4542 let n = 1;
4543 let m = fun_name()?;
4544 let h = 1 + m;
4545 Ok(())
4546}
4547
4548fn $0fun_name() -> Result<i32, i64> {
4549 let k = foo()?;
4550 if k == 42 {
4551 return Err(1);
4552 }
4553 let m = k + 1;
4554 Ok(m)
4555}
4556"#,
4557 );
4558 }
4559
4560 #[test]
4561 fn try_and_break() {
4562 cov_mark::check!(external_control_flow_try_and_bc);
4563 check_assist_not_applicable(
4564 extract_function,
4565 r#"
4566//- minicore: option
4567fn foo() -> Option<()> {
4568 loop {
4569 let n = Some(1);
4570 $0let m = n? + 1;
4571 break;
4572 let k = 2;
4573 let k = k + 1;$0
4574 let r = n + k;
4575 }
4576 Some(())
4577}
4578"#,
4579 );
4580 }
4581
4582 #[test]
4583 fn try_and_return_ok() {
4584 check_assist(
4585 extract_function,
4586 r#"
4587//- minicore: result, add, builtin_impls
4588fn foo() -> Result<(), i64> {
4589 let n = 1;
4590 $0let k = foo()?;
4591 if k == 42 {
4592 return Ok(1);
4593 }
4594 let m = k + 1;$0
4595 let h = 1 + m;
4596 Ok(())
4597}
4598"#,
4599 r#"
4600fn foo() -> Result<(), i64> {
4601 let n = 1;
4602 let m = fun_name()?;
4603 let h = 1 + m;
4604 Ok(())
4605}
4606
4607fn $0fun_name() -> Result<i32, i64> {
4608 let k = foo()?;
4609 if k == 42 {
4610 return Ok(1);
4611 }
4612 let m = k + 1;
4613 Ok(m)
4614}
4615"#,
4616 );
4617 }
4618
4619 #[test]
4620 fn param_usage_in_macro() {
4621 check_assist(
4622 extract_function,
4623 r#"
4624macro_rules! m {
4625 ($val:expr) => { $val };
4626}
4627
4628fn foo() {
4629 let n = 1;
4630 $0let k = n * m!(n);$0
4631 let m = k + 1;
4632}
4633"#,
4634 r#"
4635macro_rules! m {
4636 ($val:expr) => { $val };
4637}
4638
4639fn foo() {
4640 let n = 1;
4641 let k = fun_name(n);
4642 let m = k + 1;
4643}
4644
4645fn $0fun_name(n: i32) -> i32 {
4646 let k = n * m!(n);
4647 k
4648}
4649"#,
4650 );
4651 }
4652
4653 #[test]
4654 fn param_usage_in_macro_with_nested_tt() {
4655 check_assist(
4656 extract_function,
4657 r#"
4658macro_rules! m {
4659 ($val:expr) => { $val };
4660}
4661
4662fn foo() {
4663 let n = 1;
4664 let t = 1;
4665 $0let k = n * m!((n) + { t });$0
4666 let m = k + 1;
4667}
4668"#,
4669 r#"
4670macro_rules! m {
4671 ($val:expr) => { $val };
4672}
4673
4674fn foo() {
4675 let n = 1;
4676 let t = 1;
4677 let k = fun_name(n, t);
4678 let m = k + 1;
4679}
4680
4681fn $0fun_name(n: i32, t: i32) -> i32 {
4682 let k = n * m!((n) + { t });
4683 k
4684}
4685"#,
4686 )
4687 }
4688
4689 #[test]
4690 fn param_usage_in_macro_with_nested_tt_2() {
4691 check_assist(
4692 extract_function,
4693 r#"
4694macro_rules! m {
4695 ($val:expr) => { $val };
4696}
4697
4698struct S(i32);
4699impl S {
4700 fn foo(&self) {
4701 let n = 1;
4702 $0let k = n * m!((n) + { self.0 });$0
4703 let m = k + 1;
4704 }
4705}
4706"#,
4707 r#"
4708macro_rules! m {
4709 ($val:expr) => { $val };
4710}
4711
4712struct S(i32);
4713impl S {
4714 fn foo(&self) {
4715 let n = 1;
4716 let k = self.fun_name(n);
4717 let m = k + 1;
4718 }
4719
4720 fn $0fun_name(&self, n: i32) -> i32 {
4721 let k = n * m!((n) + { self.0 });
4722 k
4723 }
4724}
4725"#,
4726 )
4727 }
4728
4729 #[test]
4730 fn extract_with_await() {
4731 check_assist(
4732 extract_function,
4733 r#"
4734//- minicore: future
4735fn main() {
4736 $0some_function().await;$0
4737}
4738
4739async fn some_function() {
4740
4741}
4742"#,
4743 r#"
4744fn main() {
4745 fun_name().await;
4746}
4747
4748async fn $0fun_name() {
4749 some_function().await;
4750}
4751
4752async fn some_function() {
4753
4754}
4755"#,
4756 );
4757 }
4758
4759 #[test]
4760 fn extract_with_await_and_result_not_producing_match_expr() {
4761 check_assist(
4762 extract_function,
4763 r#"
4764//- minicore: future, result, try
4765async fn foo() -> Result<(), ()> {
4766 $0async {}.await;
4767 Err(())?$0
4768}
4769"#,
4770 r#"
4771async fn foo() -> Result<(), ()> {
4772 fun_name().await
4773}
4774
4775async fn $0fun_name() -> Result<(), ()> {
4776 async {}.await;
4777 Err(())?
4778}
4779"#,
4780 );
4781 }
4782
4783 #[test]
4784 fn extract_with_await_and_result_producing_match_expr() {
4785 check_assist(
4786 extract_function,
4787 r#"
4788//- minicore: future
4789async fn foo() -> i32 {
4790 loop {
4791 let n = 1;$0
4792 let k = async { 1 }.await;
4793 if k == 42 {
4794 break 3;
4795 }
4796 let m = k + 1;$0
4797 let h = 1 + m;
4798 }
4799}
4800"#,
4801 r#"
4802async fn foo() -> i32 {
4803 loop {
4804 let n = 1;
4805 let m = match fun_name().await {
4806 Ok(value) => value,
4807 Err(value) => break value,
4808 };
4809 let h = 1 + m;
4810 }
4811}
4812
4813async fn $0fun_name() -> Result<i32, i32> {
4814 let k = async { 1 }.await;
4815 if k == 42 {
4816 return Err(3);
4817 }
4818 let m = k + 1;
4819 Ok(m)
4820}
4821"#,
4822 );
4823 }
4824
4825 #[test]
4826 fn extract_with_await_in_args() {
4827 check_assist(
4828 extract_function,
4829 r#"
4830//- minicore: future
4831fn main() {
4832 $0function_call("a", some_function().await);$0
4833}
4834
4835async fn some_function() {
4836
4837}
4838"#,
4839 r#"
4840fn main() {
4841 fun_name().await;
4842}
4843
4844async fn $0fun_name() {
4845 function_call("a", some_function().await);
4846}
4847
4848async fn some_function() {
4849
4850}
4851"#,
4852 );
4853 }
4854
4855 #[test]
4856 fn extract_does_not_extract_standalone_blocks() {
4857 check_assist_not_applicable(
4858 extract_function,
4859 r#"
4860fn main() $0{}$0
4861"#,
4862 );
4863 }
4864
4865 #[test]
4866 fn extract_adds_comma_for_match_arm() {
4867 check_assist(
4868 extract_function,
4869 r#"
4870fn main() {
4871 match 6 {
4872 100 => $0{ 100 }$0
4873 _ => 0,
4874 };
4875}
4876"#,
4877 r#"
4878fn main() {
4879 match 6 {
4880 100 => fun_name(),
4881 _ => 0,
4882 };
4883}
4884
4885fn $0fun_name() -> i32 {
4886 100
4887}
4888"#,
4889 );
4890 check_assist(
4891 extract_function,
4892 r#"
4893fn main() {
4894 match 6 {
4895 100 => $0{ 100 }$0,
4896 _ => 0,
4897 };
4898}
4899"#,
4900 r#"
4901fn main() {
4902 match 6 {
4903 100 => fun_name(),
4904 _ => 0,
4905 };
4906}
4907
4908fn $0fun_name() -> i32 {
4909 100
4910}
4911"#,
4912 );
4913
4914 check_assist(
4916 extract_function,
4917 r#"
4918fn main() {
4919 match () {
4920 _ => $0()$0,
4921 }
4922}
4923"#,
4924 r#"
4925fn main() {
4926 match () {
4927 _ => fun_name(),
4928 }
4929}
4930
4931fn $0fun_name() {
4932 ()
4933}
4934"#,
4935 )
4936 }
4937
4938 #[test]
4939 fn extract_does_not_tear_comments_apart() {
4940 check_assist(
4941 extract_function,
4942 r#"
4943fn foo() {
4944 /*$0*/
4945 foo();
4946 foo();
4947 /*$0*/
4948}
4949"#,
4950 r#"
4951fn foo() {
4952 fun_name();
4953}
4954
4955fn $0fun_name() {
4956 /**/
4957 foo();
4958 foo();
4959 /**/
4960}
4961"#,
4962 );
4963 }
4964
4965 #[test]
4966 fn extract_does_not_tear_body_apart() {
4967 check_assist(
4968 extract_function,
4969 r#"
4970fn foo() {
4971 $0foo();
4972}$0
4973"#,
4974 r#"
4975fn foo() {
4976 fun_name();
4977}
4978
4979fn $0fun_name() {
4980 foo();
4981}
4982"#,
4983 );
4984 }
4985
4986 #[test]
4987 fn extract_does_not_wrap_res_in_res() {
4988 check_assist(
4989 extract_function,
4990 r#"
4991//- minicore: result, try
4992fn foo() -> Result<(), i64> {
4993 $0Result::<i32, i64>::Ok(0)?;
4994 Ok(())$0
4995}
4996"#,
4997 r#"
4998fn foo() -> Result<(), i64> {
4999 fun_name()
5000}
5001
5002fn $0fun_name() -> Result<(), i64> {
5003 Result::<i32, i64>::Ok(0)?;
5004 Ok(())
5005}
5006"#,
5007 );
5008 }
5009
5010 #[test]
5011 fn extract_knows_const() {
5012 check_assist(
5013 extract_function,
5014 r#"
5015const fn foo() {
5016 $0()$0
5017}
5018"#,
5019 r#"
5020const fn foo() {
5021 fun_name();
5022}
5023
5024const fn $0fun_name() {
5025 ()
5026}
5027"#,
5028 );
5029 check_assist(
5030 extract_function,
5031 r#"
5032const FOO: () = {
5033 $0()$0
5034};
5035"#,
5036 r#"
5037const FOO: () = {
5038 fun_name();
5039};
5040
5041const fn $0fun_name() {
5042 ()
5043}
5044"#,
5045 );
5046 }
5047
5048 #[test]
5049 fn extract_does_not_move_outer_loop_vars() {
5050 check_assist(
5051 extract_function,
5052 r#"
5053//- minicore: iterator
5054fn foo() {
5055 let mut x = 5;
5056 for _ in 0..10 {
5057 $0x += 1;$0
5058 }
5059}
5060"#,
5061 r#"
5062fn foo() {
5063 let mut x = 5;
5064 for _ in 0..10 {
5065 fun_name(&mut x);
5066 }
5067}
5068
5069fn $0fun_name(x: &mut i32) {
5070 *x += 1;
5071}
5072"#,
5073 );
5074 check_assist(
5075 extract_function,
5076 r#"
5077//- minicore: iterator
5078fn foo() {
5079 for _ in 0..10 {
5080 let mut x = 5;
5081 $0x += 1;$0
5082 }
5083}
5084"#,
5085 r#"
5086fn foo() {
5087 for _ in 0..10 {
5088 let mut x = 5;
5089 fun_name(x);
5090 }
5091}
5092
5093fn $0fun_name(mut x: i32) {
5094 x += 1;
5095}
5096"#,
5097 );
5098 check_assist(
5099 extract_function,
5100 r#"
5101//- minicore: iterator
5102fn foo() {
5103 loop {
5104 let mut x = 5;
5105 for _ in 0..10 {
5106 $0x += 1;$0
5107 }
5108 }
5109}
5110"#,
5111 r#"
5112fn foo() {
5113 loop {
5114 let mut x = 5;
5115 for _ in 0..10 {
5116 fun_name(&mut x);
5117 }
5118 }
5119}
5120
5121fn $0fun_name(x: &mut i32) {
5122 *x += 1;
5123}
5124"#,
5125 );
5126 }
5127
5128 #[test]
5130 fn extract_mut_ref_param_has_no_mut_binding_in_loop() {
5131 check_assist(
5132 extract_function,
5133 r#"
5134struct Foo;
5135impl Foo {
5136 fn foo(&mut self) {}
5137}
5138fn foo() {
5139 let mut x = Foo;
5140 while false {
5141 let y = &mut x;
5142 $0y.foo();$0
5143 }
5144 let z = x;
5145}
5146"#,
5147 r#"
5148struct Foo;
5149impl Foo {
5150 fn foo(&mut self) {}
5151}
5152fn foo() {
5153 let mut x = Foo;
5154 while false {
5155 let y = &mut x;
5156 fun_name(y);
5157 }
5158 let z = x;
5159}
5160
5161fn $0fun_name(y: &mut Foo) {
5162 y.foo();
5163}
5164"#,
5165 );
5166 }
5167
5168 #[test]
5169 fn extract_with_macro_arg() {
5170 check_assist(
5171 extract_function,
5172 r#"
5173macro_rules! m {
5174 ($val:expr) => { $val };
5175}
5176fn main() {
5177 let bar = "bar";
5178 $0m!(bar);$0
5179}
5180"#,
5181 r#"
5182macro_rules! m {
5183 ($val:expr) => { $val };
5184}
5185fn main() {
5186 let bar = "bar";
5187 fun_name(bar);
5188}
5189
5190fn $0fun_name(bar: &str) {
5191 m!(bar);
5192}
5193"#,
5194 );
5195 }
5196
5197 #[test]
5198 fn unresolvable_types_default_to_placeholder() {
5199 check_assist(
5200 extract_function,
5201 r#"
5202fn foo() {
5203 let a = __unresolved;
5204 let _ = $0{a}$0;
5205}
5206"#,
5207 r#"
5208fn foo() {
5209 let a = __unresolved;
5210 let _ = fun_name(a);
5211}
5212
5213fn $0fun_name(a: _) -> _ {
5214 a
5215}
5216"#,
5217 );
5218 }
5219
5220 #[test]
5221 fn reference_mutable_param_with_further_usages() {
5222 check_assist(
5223 extract_function,
5224 r#"
5225pub struct Foo {
5226 field: u32,
5227}
5228
5229pub fn testfn(arg: &mut Foo) {
5230 $0arg.field = 8;$0
5231 // Simulating access after the extracted portion
5232 arg.field = 16;
5233}
5234"#,
5235 r#"
5236pub struct Foo {
5237 field: u32,
5238}
5239
5240pub fn testfn(arg: &mut Foo) {
5241 fun_name(arg);
5242 // Simulating access after the extracted portion
5243 arg.field = 16;
5244}
5245
5246fn $0fun_name(arg: &mut Foo) {
5247 arg.field = 8;
5248}
5249"#,
5250 );
5251 }
5252
5253 #[test]
5254 fn reference_mutable_param_without_further_usages() {
5255 check_assist(
5256 extract_function,
5257 r#"
5258pub struct Foo {
5259 field: u32,
5260}
5261
5262pub fn testfn(arg: &mut Foo) {
5263 $0arg.field = 8;$0
5264}
5265"#,
5266 r#"
5267pub struct Foo {
5268 field: u32,
5269}
5270
5271pub fn testfn(arg: &mut Foo) {
5272 fun_name(arg);
5273}
5274
5275fn $0fun_name(arg: &mut Foo) {
5276 arg.field = 8;
5277}
5278"#,
5279 );
5280 }
5281 #[test]
5282 fn does_not_import_control_flow() {
5283 check_assist(
5284 extract_function,
5285 r#"
5286//- minicore: try
5287fn func() {
5288 $0let cf = "I'm ControlFlow";$0
5289}
5290"#,
5291 r#"
5292fn func() {
5293 fun_name();
5294}
5295
5296fn $0fun_name() {
5297 let cf = "I'm ControlFlow";
5298}
5299"#,
5300 );
5301 }
5302
5303 #[test]
5304 fn extract_function_copies_comment_at_start() {
5305 check_assist(
5306 extract_function,
5307 r#"
5308fn func() {
5309 let i = 0;
5310 $0// comment here!
5311 let x = 0;$0
5312}
5313"#,
5314 r#"
5315fn func() {
5316 let i = 0;
5317 fun_name();
5318}
5319
5320fn $0fun_name() {
5321 // comment here!
5322 let x = 0;
5323}
5324"#,
5325 );
5326 }
5327
5328 #[test]
5329 fn extract_function_copies_comment_in_between() {
5330 check_assist(
5331 extract_function,
5332 r#"
5333fn func() {
5334 let i = 0;$0
5335 let a = 0;
5336 // comment here!
5337 let x = 0;$0
5338}
5339"#,
5340 r#"
5341fn func() {
5342 let i = 0;
5343 fun_name();
5344}
5345
5346fn $0fun_name() {
5347 let a = 0;
5348 // comment here!
5349 let x = 0;
5350}
5351"#,
5352 );
5353 }
5354
5355 #[test]
5356 fn extract_function_copies_comment_at_end() {
5357 check_assist(
5358 extract_function,
5359 r#"
5360fn func() {
5361 let i = 0;
5362 $0let x = 0;
5363 // comment here!$0
5364}
5365"#,
5366 r#"
5367fn func() {
5368 let i = 0;
5369 fun_name();
5370}
5371
5372fn $0fun_name() {
5373 let x = 0;
5374 // comment here!
5375}
5376"#,
5377 );
5378 }
5379
5380 #[test]
5381 fn extract_function_copies_comment_indented() {
5382 check_assist(
5383 extract_function,
5384 r#"
5385fn func() {
5386 let i = 0;
5387 $0let x = 0;
5388 while(true) {
5389 // comment here!
5390 }$0
5391}
5392"#,
5393 r#"
5394fn func() {
5395 let i = 0;
5396 fun_name();
5397}
5398
5399fn $0fun_name() {
5400 let x = 0;
5401 while(true) {
5402 // comment here!
5403 }
5404}
5405"#,
5406 );
5407 }
5408
5409 #[test]
5410 fn extract_function_does_preserve_whitespace() {
5411 check_assist(
5412 extract_function,
5413 r#"
5414fn func() {
5415 let i = 0;
5416 $0let a = 0;
5417
5418 let x = 0;$0
5419}
5420"#,
5421 r#"
5422fn func() {
5423 let i = 0;
5424 fun_name();
5425}
5426
5427fn $0fun_name() {
5428 let a = 0;
5429
5430 let x = 0;
5431}
5432"#,
5433 );
5434 }
5435
5436 #[test]
5437 fn extract_function_long_form_comment() {
5438 check_assist(
5439 extract_function,
5440 r#"
5441fn func() {
5442 let i = 0;
5443 $0/* a comment */
5444 let x = 0;$0
5445}
5446"#,
5447 r#"
5448fn func() {
5449 let i = 0;
5450 fun_name();
5451}
5452
5453fn $0fun_name() {
5454 /* a comment */
5455 let x = 0;
5456}
5457"#,
5458 );
5459 }
5460
5461 #[test]
5462 fn it_should_not_generate_duplicate_function_names() {
5463 check_assist(
5464 extract_function,
5465 r#"
5466fn fun_name() {
5467 $0let x = 0;$0
5468}
5469"#,
5470 r#"
5471fn fun_name() {
5472 fun_name1();
5473}
5474
5475fn $0fun_name1() {
5476 let x = 0;
5477}
5478"#,
5479 );
5480 }
5481
5482 #[test]
5483 fn should_increment_suffix_until_it_finds_space() {
5484 check_assist(
5485 extract_function,
5486 r#"
5487fn fun_name1() {
5488 let y = 0;
5489}
5490
5491fn fun_name() {
5492 $0let x = 0;$0
5493}
5494"#,
5495 r#"
5496fn fun_name1() {
5497 let y = 0;
5498}
5499
5500fn fun_name() {
5501 fun_name2();
5502}
5503
5504fn $0fun_name2() {
5505 let x = 0;
5506}
5507"#,
5508 );
5509 }
5510
5511 #[test]
5512 fn extract_method_from_trait_impl() {
5513 check_assist(
5514 extract_function,
5515 r#"
5516struct Struct(i32);
5517trait Trait {
5518 fn bar(&self) -> i32;
5519}
5520
5521impl Trait for Struct {
5522 fn bar(&self) -> i32 {
5523 $0self.0 + 2$0
5524 }
5525}
5526"#,
5527 r#"
5528struct Struct(i32);
5529trait Trait {
5530 fn bar(&self) -> i32;
5531}
5532
5533impl Trait for Struct {
5534 fn bar(&self) -> i32 {
5535 self.fun_name()
5536 }
5537}
5538
5539impl Struct {
5540 fn $0fun_name(&self) -> i32 {
5541 self.0 + 2
5542 }
5543}
5544"#,
5545 );
5546 }
5547
5548 #[test]
5549 fn extract_method_from_trait_with_existing_non_empty_impl_block() {
5550 check_assist(
5551 extract_function,
5552 r#"
5553struct Struct(i32);
5554trait Trait {
5555 fn bar(&self) -> i32;
5556}
5557
5558impl Struct {
5559 fn foo() {}
5560}
5561
5562impl Trait for Struct {
5563 fn bar(&self) -> i32 {
5564 $0self.0 + 2$0
5565 }
5566}
5567"#,
5568 r#"
5569struct Struct(i32);
5570trait Trait {
5571 fn bar(&self) -> i32;
5572}
5573
5574impl Struct {
5575 fn foo() {}
5576
5577 fn $0fun_name(&self) -> i32 {
5578 self.0 + 2
5579 }
5580}
5581
5582impl Trait for Struct {
5583 fn bar(&self) -> i32 {
5584 self.fun_name()
5585 }
5586}
5587"#,
5588 )
5589 }
5590
5591 #[test]
5592 fn extract_function_from_trait_with_existing_non_empty_impl_block() {
5593 check_assist(
5594 extract_function,
5595 r#"
5596struct Struct(i32);
5597trait Trait {
5598 fn bar(&self) -> i32;
5599}
5600
5601impl Struct {
5602 fn foo() {}
5603}
5604
5605impl Trait for Struct {
5606 fn bar(&self) -> i32 {
5607 let three_squared = $03 * 3$0;
5608 self.0 + three_squared
5609 }
5610}
5611"#,
5612 r#"
5613struct Struct(i32);
5614trait Trait {
5615 fn bar(&self) -> i32;
5616}
5617
5618impl Struct {
5619 fn foo() {}
5620}
5621
5622impl Trait for Struct {
5623 fn bar(&self) -> i32 {
5624 let three_squared = three_squared();
5625 self.0 + three_squared
5626 }
5627}
5628
5629fn $0three_squared() -> i32 {
5630 3 * 3
5631}
5632"#,
5633 )
5634 }
5635
5636 #[test]
5637 fn extract_method_from_trait_with_multiple_existing_impl_blocks() {
5638 check_assist(
5639 extract_function,
5640 r#"
5641struct Struct(i32);
5642struct StructBefore(i32);
5643struct StructAfter(i32);
5644trait Trait {
5645 fn bar(&self) -> i32;
5646}
5647
5648impl StructBefore {
5649 fn foo(){}
5650}
5651
5652impl Struct {
5653 fn foo(){}
5654}
5655
5656impl StructAfter {
5657 fn foo(){}
5658}
5659
5660impl Trait for Struct {
5661 fn bar(&self) -> i32 {
5662 $0self.0 + 2$0
5663 }
5664}
5665"#,
5666 r#"
5667struct Struct(i32);
5668struct StructBefore(i32);
5669struct StructAfter(i32);
5670trait Trait {
5671 fn bar(&self) -> i32;
5672}
5673
5674impl StructBefore {
5675 fn foo(){}
5676}
5677
5678impl Struct {
5679 fn foo(){}
5680
5681 fn $0fun_name(&self) -> i32 {
5682 self.0 + 2
5683 }
5684}
5685
5686impl StructAfter {
5687 fn foo(){}
5688}
5689
5690impl Trait for Struct {
5691 fn bar(&self) -> i32 {
5692 self.fun_name()
5693 }
5694}
5695"#,
5696 )
5697 }
5698
5699 #[test]
5700 fn extract_method_from_trait_with_multiple_existing_trait_impl_blocks() {
5701 check_assist(
5702 extract_function,
5703 r#"
5704struct Struct(i32);
5705trait Trait {
5706 fn bar(&self) -> i32;
5707}
5708trait TraitBefore {
5709 fn before(&self) -> i32;
5710}
5711trait TraitAfter {
5712 fn after(&self) -> i32;
5713}
5714
5715impl TraitBefore for Struct {
5716 fn before(&self) -> i32 {
5717 42
5718 }
5719}
5720
5721impl Struct {
5722 fn foo(){}
5723}
5724
5725impl TraitAfter for Struct {
5726 fn after(&self) -> i32 {
5727 42
5728 }
5729}
5730
5731impl Trait for Struct {
5732 fn bar(&self) -> i32 {
5733 $0self.0 + 2$0
5734 }
5735}
5736"#,
5737 r#"
5738struct Struct(i32);
5739trait Trait {
5740 fn bar(&self) -> i32;
5741}
5742trait TraitBefore {
5743 fn before(&self) -> i32;
5744}
5745trait TraitAfter {
5746 fn after(&self) -> i32;
5747}
5748
5749impl TraitBefore for Struct {
5750 fn before(&self) -> i32 {
5751 42
5752 }
5753}
5754
5755impl Struct {
5756 fn foo(){}
5757
5758 fn $0fun_name(&self) -> i32 {
5759 self.0 + 2
5760 }
5761}
5762
5763impl TraitAfter for Struct {
5764 fn after(&self) -> i32 {
5765 42
5766 }
5767}
5768
5769impl Trait for Struct {
5770 fn bar(&self) -> i32 {
5771 self.fun_name()
5772 }
5773}
5774"#,
5775 )
5776 }
5777
5778 #[test]
5779 fn closure_arguments() {
5780 check_assist(
5781 extract_function,
5782 r#"
5783fn parent(factor: i32) {
5784 let v = &[1, 2, 3];
5785
5786 $0v.iter().map(|it| it * factor);$0
5787}
5788"#,
5789 r#"
5790fn parent(factor: i32) {
5791 let v = &[1, 2, 3];
5792
5793 fun_name(factor, v);
5794}
5795
5796fn $0fun_name(factor: i32, v: &[i32; 3]) {
5797 v.iter().map(|it| it * factor);
5798}
5799"#,
5800 );
5801 }
5802
5803 #[test]
5804 fn preserve_generics() {
5805 check_assist(
5806 extract_function,
5807 r#"
5808fn func<T: Debug>(i: T) {
5809 $0foo(i);$0
5810}
5811"#,
5812 r#"
5813fn func<T: Debug>(i: T) {
5814 fun_name(i);
5815}
5816
5817fn $0fun_name<T: Debug>(i: T) {
5818 foo(i);
5819}
5820"#,
5821 );
5822 }
5823
5824 #[test]
5825 fn dont_emit_type_with_hidden_lifetime_parameter() {
5826 check_assist(
5828 extract_function,
5829 r#"
5830struct Struct<'a, T>(&'a T);
5831fn func<T: Debug>(i: Struct<'_, T>) {
5832 $0foo(i);$0
5833}
5834"#,
5835 r#"
5836struct Struct<'a, T>(&'a T);
5837fn func<T: Debug>(i: Struct<'_, T>) {
5838 fun_name(i);
5839}
5840
5841fn $0fun_name(i: Struct<'_, T>) {
5842 foo(i);
5843}
5844"#,
5845 );
5846 }
5847
5848 #[test]
5849 fn preserve_generics_from_body() {
5850 check_assist(
5851 extract_function,
5852 r#"
5853fn func<T: Default>() -> T {
5854 $0T::default()$0
5855}
5856"#,
5857 r#"
5858fn func<T: Default>() -> T {
5859 fun_name()
5860}
5861
5862fn $0fun_name<T: Default>() -> T {
5863 T::default()
5864}
5865"#,
5866 );
5867 }
5868
5869 #[test]
5870 fn filter_unused_generics() {
5871 check_assist(
5872 extract_function,
5873 r#"
5874fn func<T: Debug, U: Copy>(i: T, u: U) {
5875 bar(u);
5876 $0foo(i);$0
5877}
5878"#,
5879 r#"
5880fn func<T: Debug, U: Copy>(i: T, u: U) {
5881 bar(u);
5882 fun_name(i);
5883}
5884
5885fn $0fun_name<T: Debug>(i: T) {
5886 foo(i);
5887}
5888"#,
5889 );
5890 }
5891
5892 #[test]
5893 fn empty_generic_param_list() {
5894 check_assist(
5895 extract_function,
5896 r#"
5897fn func<T: Debug>(t: T, i: u32) {
5898 bar(t);
5899 $0foo(i);$0
5900}
5901"#,
5902 r#"
5903fn func<T: Debug>(t: T, i: u32) {
5904 bar(t);
5905 fun_name(i);
5906}
5907
5908fn $0fun_name(i: u32) {
5909 foo(i);
5910}
5911"#,
5912 );
5913 }
5914
5915 #[test]
5916 fn preserve_where_clause() {
5917 check_assist(
5918 extract_function,
5919 r#"
5920fn func<T>(i: T) where T: Debug {
5921 $0foo(i);$0
5922}
5923"#,
5924 r#"
5925fn func<T>(i: T) where T: Debug {
5926 fun_name(i);
5927}
5928
5929fn $0fun_name<T>(i: T) where T: Debug {
5930 foo(i);
5931}
5932"#,
5933 );
5934 }
5935
5936 #[test]
5937 fn filter_unused_where_clause() {
5938 check_assist(
5939 extract_function,
5940 r#"
5941fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
5942 bar(u);
5943 $0foo(i);$0
5944}
5945"#,
5946 r#"
5947fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
5948 bar(u);
5949 fun_name(i);
5950}
5951
5952fn $0fun_name<T>(i: T) where T: Debug {
5953 foo(i);
5954}
5955"#,
5956 );
5957 }
5958
5959 #[test]
5960 fn nested_generics() {
5961 check_assist(
5962 extract_function,
5963 r#"
5964struct Struct<T: Into<i32>>(T);
5965impl <T: Into<i32> + Copy> Struct<T> {
5966 fn func<V: Into<i32>>(&self, v: V) -> i32 {
5967 let t = self.0;
5968 $0t.into() + v.into()$0
5969 }
5970}
5971"#,
5972 r#"
5973struct Struct<T: Into<i32>>(T);
5974impl <T: Into<i32> + Copy> Struct<T> {
5975 fn func<V: Into<i32>>(&self, v: V) -> i32 {
5976 let t = self.0;
5977 fun_name(v, t)
5978 }
5979}
5980
5981fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(v: V, t: T) -> i32 {
5982 t.into() + v.into()
5983}
5984"#,
5985 );
5986 }
5987
5988 #[test]
5989 fn filters_unused_nested_generics() {
5990 check_assist(
5991 extract_function,
5992 r#"
5993struct Struct<T: Into<i32>, U: Debug>(T, U);
5994impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> {
5995 fn func<V: Into<i32>>(&self, v: V) -> i32 {
5996 let t = self.0;
5997 $0t.into() + v.into()$0
5998 }
5999}
6000"#,
6001 r#"
6002struct Struct<T: Into<i32>, U: Debug>(T, U);
6003impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> {
6004 fn func<V: Into<i32>>(&self, v: V) -> i32 {
6005 let t = self.0;
6006 fun_name(v, t)
6007 }
6008}
6009
6010fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(v: V, t: T) -> i32 {
6011 t.into() + v.into()
6012}
6013"#,
6014 );
6015 }
6016
6017 #[test]
6018 fn nested_where_clauses() {
6019 check_assist(
6020 extract_function,
6021 r#"
6022struct Struct<T>(T) where T: Into<i32>;
6023impl <T> Struct<T> where T: Into<i32> + Copy {
6024 fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
6025 let t = self.0;
6026 $0t.into() + v.into()$0
6027 }
6028}
6029"#,
6030 r#"
6031struct Struct<T>(T) where T: Into<i32>;
6032impl <T> Struct<T> where T: Into<i32> + Copy {
6033 fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
6034 let t = self.0;
6035 fun_name(v, t)
6036 }
6037}
6038
6039fn $0fun_name<T, V>(v: V, t: T) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
6040 t.into() + v.into()
6041}
6042"#,
6043 );
6044 }
6045
6046 #[test]
6047 fn filters_unused_nested_where_clauses() {
6048 check_assist(
6049 extract_function,
6050 r#"
6051struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug;
6052impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug {
6053 fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
6054 let t = self.0;
6055 $0t.into() + v.into()$0
6056 }
6057}
6058"#,
6059 r#"
6060struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug;
6061impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug {
6062 fn func<V>(&self, v: V) -> i32 where V: Into<i32> {
6063 let t = self.0;
6064 fun_name(v, t)
6065 }
6066}
6067
6068fn $0fun_name<T, V>(v: V, t: T) -> i32 where T: Into<i32> + Copy, V: Into<i32> {
6069 t.into() + v.into()
6070}
6071"#,
6072 );
6073 }
6074
6075 #[test]
6076 fn tail_expr_no_extra_control_flow() {
6077 check_assist(
6078 extract_function,
6079 r#"
6080//- minicore: result
6081fn fallible() -> Result<(), ()> {
6082 $0if true {
6083 return Err(());
6084 }
6085 Ok(())$0
6086}
6087"#,
6088 r#"
6089fn fallible() -> Result<(), ()> {
6090 fun_name()
6091}
6092
6093fn $0fun_name() -> Result<(), ()> {
6094 if true {
6095 return Err(());
6096 }
6097 Ok(())
6098}
6099"#,
6100 );
6101 }
6102
6103 #[test]
6104 fn non_tail_expr_of_tail_expr_loop() {
6105 check_assist(
6106 extract_function,
6107 r#"
6108pub fn f() {
6109 loop {
6110 $0if true {
6111 continue;
6112 }$0
6113
6114 if false {
6115 break;
6116 }
6117 }
6118}
6119"#,
6120 r#"
6121pub fn f() {
6122 loop {
6123 if let ControlFlow::Break(_) = fun_name() {
6124 continue;
6125 }
6126
6127 if false {
6128 break;
6129 }
6130 }
6131}
6132
6133fn $0fun_name() -> ControlFlow<()> {
6134 if true {
6135 return ControlFlow::Break(());
6136 }
6137 ControlFlow::Continue(())
6138}
6139"#,
6140 );
6141 }
6142
6143 #[test]
6144 fn non_tail_expr_of_tail_if_block() {
6145 check_assist(
6147 extract_function,
6148 r#"
6149//- minicore: option, try
6150fn f() -> Option<()> {
6151 if true {
6152 let a = $0if true {
6153 Some(())?
6154 } else {
6155 ()
6156 }$0;
6157 Some(a)
6158 } else {
6159 None
6160 }
6161}
6162"#,
6163 r#"
6164fn f() -> Option<()> {
6165 if true {
6166 let a = fun_name()?;;
6167 Some(a)
6168 } else {
6169 None
6170 }
6171}
6172
6173fn $0fun_name() -> Option<()> {
6174 Some(if true {
6175 Some(())?
6176 } else {
6177 ()
6178 })
6179}
6180"#,
6181 );
6182 }
6183
6184 #[test]
6185 fn tail_expr_of_tail_block_nested() {
6186 check_assist(
6187 extract_function,
6188 r#"
6189//- minicore: option, try
6190fn f() -> Option<()> {
6191 if true {
6192 $0{
6193 let a = if true {
6194 Some(())?
6195 } else {
6196 ()
6197 };
6198 Some(a)
6199 }$0
6200 } else {
6201 None
6202 }
6203}
6204"#,
6205 r#"
6206fn f() -> Option<()> {
6207 if true {
6208 fun_name()
6209 } else {
6210 None
6211 }
6212}
6213
6214fn $0fun_name() -> Option<()> {
6215 let a = if true {
6216 Some(())?
6217 } else {
6218 ()
6219 };
6220 Some(a)
6221}
6222"#,
6223 );
6224 }
6225
6226 #[test]
6227 fn non_tail_expr_with_comment_of_tail_expr_loop() {
6228 check_assist(
6229 extract_function,
6230 r#"
6231pub fn f() {
6232 loop {
6233 $0// A comment
6234 if true {
6235 continue;
6236 }$0
6237 if false {
6238 break;
6239 }
6240 }
6241}
6242"#,
6243 r#"
6244pub fn f() {
6245 loop {
6246 if let ControlFlow::Break(_) = fun_name() {
6247 continue;
6248 }
6249 if false {
6250 break;
6251 }
6252 }
6253}
6254
6255fn $0fun_name() -> ControlFlow<()> {
6256 // A comment
6257 if true {
6258 return ControlFlow::Break(());
6259 }
6260 ControlFlow::Continue(())
6261}
6262"#,
6263 );
6264 }
6265
6266 #[test]
6267 fn comments_in_block_expr() {
6268 check_assist(
6269 extract_function,
6270 r#"
6271fn f() {
6272 let c = $0{
6273 // comment 1
6274 let a = 2 + 3;
6275 // comment 2
6276 let b = 5;
6277 a + b
6278 }$0;
6279}
6280"#,
6281 r#"
6282fn f() {
6283 let c = fun_name();
6284}
6285
6286fn $0fun_name() -> i32 {
6287 // comment 1
6288 let a = 2 + 3;
6289 // comment 2
6290 let b = 5;
6291 a + b
6292}
6293"#,
6294 );
6295 }
6296
6297 #[test]
6298 fn sort_params_in_order() {
6299 check_assist(
6300 extract_function,
6301 r#"
6302fn existing(a: i32, b: i32, c: i32) {
6303 let x = 32;
6304
6305 let p = $0x + b + c + a$0;
6306}
6307"#,
6308 r#"
6309fn existing(a: i32, b: i32, c: i32) {
6310 let x = 32;
6311
6312 let p = fun_name(a, b, c, x);
6313}
6314
6315fn $0fun_name(a: i32, b: i32, c: i32, x: i32) -> i32 {
6316 x + b + c + a
6317}
6318"#,
6319 );
6320 }
6321
6322 #[test]
6323 fn fmt_macro_argument() {
6324 check_assist(
6325 extract_function,
6326 r#"
6327//- minicore: fmt
6328fn existing(a: i32, b: i32, c: i32) {
6329 $0print!("{a}{}{}", b, "{c}");$0
6330}
6331"#,
6332 r#"
6333fn existing(a: i32, b: i32, c: i32) {
6334 fun_name(a, b);
6335}
6336
6337fn $0fun_name(a: i32, b: i32) {
6338 print!("{a}{}{}", b, "{c}");
6339}
6340"#,
6341 );
6342 }
6343
6344 #[test]
6345 fn in_left_curly_is_not_applicable() {
6346 cov_mark::check!(extract_function_in_braces_is_not_applicable);
6347 check_assist_not_applicable(extract_function, r"fn foo() { $0}$0");
6348 }
6349
6350 #[test]
6351 fn in_right_curly_is_not_applicable() {
6352 cov_mark::check!(extract_function_in_braces_is_not_applicable);
6353 check_assist_not_applicable(extract_function, r"fn foo() $0{$0 }");
6354 }
6355
6356 #[test]
6357 fn in_left_paren_is_not_applicable() {
6358 cov_mark::check!(extract_function_in_braces_is_not_applicable);
6359 check_assist_not_applicable(extract_function, r"fn foo( $0)$0 { }");
6360 }
6361
6362 #[test]
6363 fn in_right_paren_is_not_applicable() {
6364 cov_mark::check!(extract_function_in_braces_is_not_applicable);
6365 check_assist_not_applicable(extract_function, r"fn foo $0($0 ) { }");
6366 }
6367
6368 #[test]
6369 fn in_left_brack_is_not_applicable() {
6370 cov_mark::check!(extract_function_in_braces_is_not_applicable);
6371 check_assist_not_applicable(extract_function, r"fn foo(arr: &mut [i32$0]$0) {}");
6372 }
6373
6374 #[test]
6375 fn in_right_brack_is_not_applicable() {
6376 cov_mark::check!(extract_function_in_braces_is_not_applicable);
6377 check_assist_not_applicable(extract_function, r"fn foo(arr: &mut $0[$0i32]) {}");
6378 }
6379
6380 #[test]
6381 fn issue_20965_panic() {
6382 check_assist(
6383 extract_function,
6384 r#"
6385//- minicore: fmt
6386#[derive(Debug)]
6387struct Foo(&'static str);
6388
6389impl Foo {
6390 fn text(&self) -> &str { self.0 }
6391}
6392
6393fn main() {
6394 let s = Foo("");
6395 $0print!("{}{}", s, s);$0
6396 let _ = s.text() == "";
6397}"#,
6398 r#"
6399#[derive(Debug)]
6400struct Foo(&'static str);
6401
6402impl Foo {
6403 fn text(&self) -> &str { self.0 }
6404}
6405
6406fn main() {
6407 let s = Foo("");
6408 fun_name(&s);
6409 let _ = s.text() == "";
6410}
6411
6412fn $0fun_name(s: &Foo) {
6413 print!("{}{}", *s, *s);
6414}"#,
6415 );
6416
6417 check_assist(
6418 extract_function,
6419 r#"
6420//- minicore: fmt
6421#[derive(Debug)]
6422struct Foo(&'static str);
6423
6424impl Foo {
6425 fn text(&self) -> &str { self.0 }
6426}
6427
6428fn main() {
6429 let s = Foo("");
6430 $0print!("{s}{s}");$0
6431 let _ = s.text() == "";
6432}"#,
6433 r#"
6434#[derive(Debug)]
6435struct Foo(&'static str);
6436
6437impl Foo {
6438 fn text(&self) -> &str { self.0 }
6439}
6440
6441fn main() {
6442 let s = Foo("");
6443 fun_name(&s);
6444 let _ = s.text() == "";
6445}
6446
6447fn $0fun_name(s: &Foo) {
6448 print!("{s}{s}");
6449}"#,
6450 );
6451 }
6452
6453 #[test]
6454 fn parameter_is_added_used_in_eq_expression_in_macro() {
6455 check_assist(
6456 extract_function,
6457 r#"
6458//- minicore: fmt
6459fn foo() {
6460 let v = 123;
6461 $0print!("{v:?}{}", v == 123);$0
6462}"#,
6463 r#"
6464fn foo() {
6465 let v = 123;
6466 fun_name(v);
6467}
6468
6469fn $0fun_name(v: i32) {
6470 print!("{v:?}{}", v == 123);
6471}"#,
6472 );
6473 }
6474
6475 #[test]
6476 fn no_parameter_for_variable_used_only_let_else() {
6477 check_assist(
6478 extract_function,
6479 r#"
6480fn foo() -> u32 {
6481 let x = 5;
6482
6483 $0let Some(y) = Some(1) else {
6484 return x * 2;
6485 };$0
6486
6487 y
6488}"#,
6489 r#"
6490fn foo() -> u32 {
6491 let x = 5;
6492
6493 let y = match fun_name(x) {
6494 Ok(value) => value,
6495 Err(value) => return value,
6496 };
6497
6498 y
6499}
6500
6501fn $0fun_name(x: u32) -> Result<_, u32> {
6502 let Some(y) = Some(1) else {
6503 return Err(x * 2);
6504 };
6505 Ok(y)
6506}"#,
6507 );
6508 }
6509
6510 #[test]
6511 fn deeply_nested_macros() {
6512 check_assist(
6513 extract_function,
6514 r#"
6515macro_rules! m {
6516 ($val:ident) => { $val };
6517}
6518
6519macro_rules! n {
6520 ($v1:ident, $v2:ident) => { m!($v1) + $v2 };
6521}
6522
6523macro_rules! o {
6524 ($v1:ident, $v2:ident, $v3:ident) => { n!($v1, $v2) + $v3 };
6525}
6526
6527fn foo() -> u32 {
6528 let v1 = 1;
6529 let v2 = 2;
6530 $0let v3 = 3;
6531 o!(v1, v2, v3)$0
6532}"#,
6533 r#"
6534macro_rules! m {
6535 ($val:ident) => { $val };
6536}
6537
6538macro_rules! n {
6539 ($v1:ident, $v2:ident) => { m!($v1) + $v2 };
6540}
6541
6542macro_rules! o {
6543 ($v1:ident, $v2:ident, $v3:ident) => { n!($v1, $v2) + $v3 };
6544}
6545
6546fn foo() -> u32 {
6547 let v1 = 1;
6548 let v2 = 2;
6549 fun_name(v1, v2)
6550}
6551
6552fn $0fun_name(v1: u32, v2: u32) -> u32 {
6553 let v3 = 3;
6554 o!(v1, v2, v3)
6555}"#,
6556 );
6557 }
6558
6559 #[test]
6560 fn pattern_assignment() {
6561 check_assist(
6562 extract_function,
6563 r#"
6564struct Point {x: u32, y: u32};
6565
6566fn point() -> Point {
6567 Point { x: 45, y: 50 };
6568}
6569
6570fn foo() {
6571 let mut a = 1;
6572 let mut b = 3;
6573 $0Point { x: a, y: b } = point();$0
6574}
6575"#,
6576 r#"
6577struct Point {x: u32, y: u32};
6578
6579fn point() -> Point {
6580 Point { x: 45, y: 50 };
6581}
6582
6583fn foo() {
6584 let mut a = 1;
6585 let mut b = 3;
6586 fun_name(a, b);
6587}
6588
6589fn $0fun_name(mut a: u32, mut b: u32) {
6590 Point { x: a, y: b } = point();
6591}
6592"#,
6593 );
6594 }
6595
6596 #[test]
6597 fn tuple_assignment() {
6598 check_assist(
6599 extract_function,
6600 r#"
6601fn foo() {
6602 let mut a = 3;
6603 let mut b = 4;
6604 $0(a, b) = (b, a);$0
6605}
6606"#,
6607 r#"
6608fn foo() {
6609 let mut a = 3;
6610 let mut b = 4;
6611 fun_name(a, b);
6612}
6613
6614fn $0fun_name(mut a: i32, mut b: i32) {
6615 (a, b) = (b, a);
6616}
6617"#,
6618 );
6619 }
6620
6621 #[test]
6622 fn with_cfg_attr() {
6623 check_assist(
6624 extract_function,
6625 r#"
6626//- /main.rs crate:main cfg:test
6627#[cfg(test)]
6628fn foo() {
6629 foo($01 + 1$0);
6630}
6631"#,
6632 r#"
6633#[cfg(test)]
6634fn foo() {
6635 foo(fun_name());
6636}
6637
6638#[cfg(test)]
6639fn $0fun_name() -> i32 {
6640 1 + 1
6641}
6642"#,
6643 );
6644 }
6645
6646 #[test]
6647 fn with_track_caller() {
6648 check_assist(
6649 extract_function,
6650 r#"
6651#[track_caller]
6652fn foo() {
6653 foo($01 + 1$0);
6654}
6655"#,
6656 r#"
6657#[track_caller]
6658fn foo() {
6659 foo(fun_name());
6660}
6661
6662#[track_caller]
6663fn $0fun_name() -> i32 {
6664 1 + 1
6665}
6666"#,
6667 );
6668 }
6669}