5 use hir::{HirDisplay, Local};
7 defs::{Definition, NameRefClass},
8 search::{FileReference, ReferenceAccess, SearchScope},
10 use itertools::Itertools;
16 edit::{AstNodeEdit, IndentLevel},
20 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR},
21 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
25 assist_context::{AssistContext, Assists},
29 // Assist: extract_function
31 // Extracts selected statements into new function.
49 // fn $0fun_name(n: i32) {
54 pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
55 if ctx.frange.range.is_empty() {
59 let node = ctx.covering_element();
60 if node.kind() == COMMENT {
61 cov_mark::hit!(extract_function_in_comment_is_not_applicable);
65 let node = element_to_node(node);
67 let body = extraction_target(&node, ctx.frange.range)?;
69 let vars_used_in_body = vars_used_in_body(ctx, &body);
70 let self_param = self_param_from_usages(ctx, &body, &vars_used_in_body);
72 let anchor = if self_param.is_some() { Anchor::Method } else { Anchor::Freestanding };
73 let insert_after = scope_for_fn_insertion(&body, anchor)?;
74 let module = ctx.sema.scope(&insert_after).module()?;
76 let vars_defined_in_body_and_outlive = vars_defined_in_body_and_outlive(ctx, &body);
77 let ret_ty = body_return_ty(ctx, &body)?;
79 // FIXME: we compute variables that outlive here just to check `never!` condition
80 // this requires traversing whole `body` (cheap) and finding all references (expensive)
81 // maybe we can move this check to `edit` closure somehow?
82 if stdx::never!(!vars_defined_in_body_and_outlive.is_empty() && !ret_ty.is_unit()) {
83 // We should not have variables that outlive body if we have expression block
86 let control_flow = external_control_flow(ctx, &body)?;
88 let target_range = body.text_range();
91 AssistId("extract_function", crate::AssistKind::RefactorExtract),
92 "Extract into function",
95 let params = extracted_function_params(ctx, &body, &vars_used_in_body);
98 name: "fun_name".to_string(),
99 self_param: self_param.map(|(_, pat)| pat),
104 vars_defined_in_body_and_outlive,
107 let new_indent = IndentLevel::from_node(&insert_after);
108 let old_indent = fun.body.indent_level();
110 builder.replace(target_range, format_replacement(ctx, &fun, old_indent));
112 let fn_def = format_function(ctx, module, &fun, old_indent, new_indent);
113 let insert_offset = insert_after.text_range().end();
114 match ctx.config.snippet_cap {
115 Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
116 None => builder.insert(insert_offset, fn_def),
122 fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<ControlFlow> {
123 let mut ret_expr = None;
124 let mut try_expr = None;
125 let mut break_expr = None;
126 let mut continue_expr = None;
127 let (syntax, text_range) = match body {
128 FunctionBody::Expr(expr) => (expr.syntax(), expr.syntax().text_range()),
129 FunctionBody::Span { parent, text_range } => (parent.syntax(), *text_range),
132 let mut nested_loop = None;
133 let mut nested_scope = None;
135 for e in syntax.preorder() {
137 WalkEvent::Enter(e) => e,
138 WalkEvent::Leave(e) => {
139 if nested_loop.as_ref() == Some(&e) {
142 if nested_scope.as_ref() == Some(&e) {
148 if nested_scope.is_some() {
151 if !text_range.contains_range(e.text_range()) {
155 SyntaxKind::LOOP_EXPR | SyntaxKind::WHILE_EXPR | SyntaxKind::FOR_EXPR => {
156 if nested_loop.is_none() {
157 nested_loop = Some(e);
164 | SyntaxKind::MODULE => {
165 if nested_scope.is_none() {
166 nested_scope = Some(e);
169 SyntaxKind::RETURN_EXPR => {
170 ret_expr = Some(ast::ReturnExpr::cast(e).unwrap());
172 SyntaxKind::TRY_EXPR => {
173 try_expr = Some(ast::TryExpr::cast(e).unwrap());
175 SyntaxKind::BREAK_EXPR if nested_loop.is_none() => {
176 break_expr = Some(ast::BreakExpr::cast(e).unwrap());
178 SyntaxKind::CONTINUE_EXPR if nested_loop.is_none() => {
179 continue_expr = Some(ast::ContinueExpr::cast(e).unwrap());
185 let kind = match (try_expr, ret_expr, break_expr, continue_expr) {
186 (Some(e), None, None, None) => {
187 let func = e.syntax().ancestors().find_map(ast::Fn::cast)?;
188 let def = ctx.sema.to_def(&func)?;
189 let ret_ty = def.ret_type(ctx.db());
190 let kind = try_kind_of_ty(ret_ty, ctx)?;
192 Some(FlowKind::Try { kind })
194 (Some(_), Some(r), None, None) => match r.expr() {
196 if let Some(kind) = expr_err_kind(&expr, ctx) {
197 Some(FlowKind::TryReturn { expr, kind })
199 cov_mark::hit!(external_control_flow_try_and_return_non_err);
205 (Some(_), _, _, _) => {
206 cov_mark::hit!(external_control_flow_try_and_bc);
209 (None, Some(r), None, None) => match r.expr() {
210 Some(expr) => Some(FlowKind::ReturnValue(expr)),
211 None => Some(FlowKind::Return),
213 (None, Some(_), _, _) => {
214 cov_mark::hit!(external_control_flow_return_and_bc);
217 (None, None, Some(_), Some(_)) => {
218 cov_mark::hit!(external_control_flow_break_and_continue);
221 (None, None, Some(b), None) => match b.expr() {
222 Some(expr) => Some(FlowKind::BreakValue(expr)),
223 None => Some(FlowKind::Break),
225 (None, None, None, Some(_)) => Some(FlowKind::Continue),
226 (None, None, None, None) => None,
229 Some(ControlFlow { kind })
232 /// Checks is expr is `Err(_)` or `None`
233 fn expr_err_kind(expr: &ast::Expr, ctx: &AssistContext) -> Option<TryKind> {
234 let func_name = match expr {
235 ast::Expr::CallExpr(call_expr) => call_expr.expr()?,
236 ast::Expr::PathExpr(_) => expr.clone(),
239 let text = func_name.syntax().text();
242 Some(TryKind::Result { ty: ctx.sema.type_of_expr(expr)? })
243 } else if text == "None" {
244 Some(TryKind::Option)
253 self_param: Option<ast::SelfParam>,
255 control_flow: ControlFlow,
258 vars_defined_in_body_and_outlive: Vec<Local>,
265 has_usages_afterwards: bool,
266 has_mut_inside_body: bool,
272 kind: Option<FlowKind>,
275 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
283 #[derive(Debug, Eq, PartialEq)]
287 Tuple(Vec<hir::Type>),
291 fn return_type(&self, ctx: &AssistContext) -> FunType {
293 RetType::Expr(ty) if ty.is_unit() => FunType::Unit,
294 RetType::Expr(ty) => FunType::Single(ty.clone()),
295 RetType::Stmt => match self.vars_defined_in_body_and_outlive.as_slice() {
297 [var] => FunType::Single(var.ty(ctx.db())),
299 let types = vars.iter().map(|v| v.ty(ctx.db())).collect();
300 FunType::Tuple(types)
308 fn is_ref(&self) -> bool {
309 matches!(self, ParamKind::SharedRef | ParamKind::MutRef)
314 fn kind(&self) -> ParamKind {
315 match (self.has_usages_afterwards, self.has_mut_inside_body, self.is_copy) {
316 (true, true, _) => ParamKind::MutRef,
317 (true, false, false) => ParamKind::SharedRef,
318 (false, true, _) => ParamKind::MutValue,
319 (true, false, true) | (false, false, _) => ParamKind::Value,
323 fn to_arg(&self, ctx: &AssistContext) -> ast::Expr {
324 let var = path_expr_from_local(ctx, self.var);
326 ParamKind::Value | ParamKind::MutValue => var,
327 ParamKind::SharedRef => make::expr_ref(var, false),
328 ParamKind::MutRef => make::expr_ref(var, true),
332 fn to_param(&self, ctx: &AssistContext, module: hir::Module) -> ast::Param {
333 let var = self.var.name(ctx.db()).unwrap().to_string();
334 let var_name = make::name(&var);
335 let pat = match self.kind() {
336 ParamKind::MutValue => make::ident_mut_pat(var_name),
337 ParamKind::Value | ParamKind::SharedRef | ParamKind::MutRef => {
338 make::ident_pat(var_name)
342 let ty = make_ty(&self.ty, ctx, module);
343 let ty = match self.kind() {
344 ParamKind::Value | ParamKind::MutValue => ty,
345 ParamKind::SharedRef => make::ty_ref(ty, false),
346 ParamKind::MutRef => make::ty_ref(ty, true),
349 make::param(pat.into(), ty)
353 /// Control flow that is exported from extracted function
365 #[derive(Debug, Clone)]
367 /// Return without value (`return;`)
369 /// Return with value (`return $expr;`)
370 ReturnValue(ast::Expr),
378 /// Break without value (`return;`)
380 /// Break with value (`break $expr;`)
381 BreakValue(ast::Expr),
386 #[derive(Debug, Clone)]
389 Result { ty: hir::Type },
393 fn make_result_handler(&self, expr: Option<ast::Expr>) -> ast::Expr {
395 FlowKind::Return | FlowKind::ReturnValue(_) => make::expr_return(expr),
396 FlowKind::Break | FlowKind::BreakValue(_) => make::expr_break(expr),
397 FlowKind::Try { .. } | FlowKind::TryReturn { .. } => {
398 stdx::never!("cannot have result handler with try");
399 expr.unwrap_or_else(|| make::expr_return(None))
401 FlowKind::Continue => {
402 stdx::always!(expr.is_none(), "continue with value is not possible");
403 make::expr_continue()
408 fn expr_ty(&self, ctx: &AssistContext) -> Option<hir::Type> {
410 FlowKind::ReturnValue(expr)
411 | FlowKind::BreakValue(expr)
412 | FlowKind::TryReturn { expr, .. } => ctx.sema.type_of_expr(expr),
413 FlowKind::Try { .. } => {
414 stdx::never!("try does not have defined expr_ty");
417 FlowKind::Return | FlowKind::Break | FlowKind::Continue => None,
422 fn try_kind_of_ty(ty: hir::Type, ctx: &AssistContext) -> Option<TryKind> {
424 // We favour Result for `expr?`
425 return Some(TryKind::Result { ty });
427 let adt = ty.as_adt()?;
428 let name = adt.name(ctx.db());
429 // FIXME: use lang items to determine if it is std type or user defined
430 // E.g. if user happens to define type named `Option`, we would have false positive
431 match name.to_string().as_str() {
432 "Option" => Some(TryKind::Option),
433 "Result" => Some(TryKind::Result { ty }),
445 fn is_unit(&self) -> bool {
447 RetType::Expr(ty) => ty.is_unit(),
448 RetType::Stmt => true,
453 /// Semantically same as `ast::Expr`, but preserves identity when using only part of the Block
457 Span { parent: ast::BlockExpr, text_range: TextRange },
461 fn from_whole_node(node: SyntaxNode) -> Option<Self> {
464 BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()).map(Self::Expr),
465 RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()).map(Self::Expr),
466 BLOCK_EXPR => ast::BlockExpr::cast(node)
467 .filter(|it| it.is_standalone())
470 _ => ast::Expr::cast(node).map(Self::Expr),
474 fn from_range(node: SyntaxNode, text_range: TextRange) -> Option<FunctionBody> {
475 let block = ast::BlockExpr::cast(node)?;
476 Some(Self::Span { parent: block, text_range })
479 fn indent_level(&self) -> IndentLevel {
481 FunctionBody::Expr(expr) => IndentLevel::from_node(expr.syntax()),
482 FunctionBody::Span { parent, .. } => IndentLevel::from_node(parent.syntax()) + 1,
486 fn tail_expr(&self) -> Option<ast::Expr> {
488 FunctionBody::Expr(expr) => Some(expr.clone()),
489 FunctionBody::Span { parent, text_range } => {
490 let tail_expr = parent.tail_expr()?;
491 if text_range.contains_range(tail_expr.syntax().text_range()) {
500 fn descendants(&self) -> impl Iterator<Item = SyntaxNode> + '_ {
502 FunctionBody::Expr(expr) => Either::Right(expr.syntax().descendants()),
503 FunctionBody::Span { parent, text_range } => Either::Left(
507 .filter(move |it| text_range.contains_range(it.text_range())),
512 fn text_range(&self) -> TextRange {
514 FunctionBody::Expr(expr) => expr.syntax().text_range(),
515 FunctionBody::Span { parent: _, text_range } => *text_range,
519 fn contains_range(&self, range: TextRange) -> bool {
520 self.text_range().contains_range(range)
523 fn preceedes_range(&self, range: TextRange) -> bool {
524 self.text_range().end() <= range.start()
527 fn contains_node(&self, node: &SyntaxNode) -> bool {
528 self.contains_range(node.text_range())
532 impl HasTokenAtOffset for FunctionBody {
533 fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
535 FunctionBody::Expr(expr) => expr.syntax().token_at_offset(offset),
536 FunctionBody::Span { parent, text_range } => {
537 match parent.syntax().token_at_offset(offset) {
538 TokenAtOffset::None => TokenAtOffset::None,
539 TokenAtOffset::Single(t) => {
540 if text_range.contains_range(t.text_range()) {
541 TokenAtOffset::Single(t)
546 TokenAtOffset::Between(a, b) => {
548 text_range.contains_range(a.text_range()),
549 text_range.contains_range(b.text_range()),
551 (true, true) => TokenAtOffset::Between(a, b),
552 (true, false) => TokenAtOffset::Single(a),
553 (false, true) => TokenAtOffset::Single(b),
554 (false, false) => TokenAtOffset::None,
563 /// node or token's parent
564 fn element_to_node(node: SyntaxElement) -> SyntaxNode {
566 syntax::NodeOrToken::Node(n) => n,
567 syntax::NodeOrToken::Token(t) => t.parent(),
571 /// Try to guess what user wants to extract
573 /// We have basically have two cases:
574 /// * We want whole node, like `loop {}`, `2 + 2`, `{ let n = 1; }` exprs.
575 /// Then we can use `ast::Expr`
576 /// * We want a few statements for a block. E.g.
578 /// fn foo() -> i32 {
588 fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<FunctionBody> {
589 // we have selected exactly the expr node
590 // wrap it before anything else
591 if node.text_range() == selection_range {
592 let body = FunctionBody::from_whole_node(node.clone());
598 // we have selected a few statements in a block
599 // so covering_element returns the whole block
600 if node.kind() == BLOCK_EXPR {
601 let body = FunctionBody::from_range(node.clone(), selection_range);
607 // we have selected single statement
608 // `from_whole_node` failed because (let) statement is not and expression
609 // so we try to expand covering_element to parent and repeat the previous
610 if let Some(parent) = node.parent() {
611 if parent.kind() == BLOCK_EXPR {
612 let body = FunctionBody::from_range(parent, selection_range);
619 // select the closest containing expr (both ifs are used)
620 std::iter::once(node.clone()).chain(node.ancestors()).find_map(FunctionBody::from_whole_node)
623 /// list local variables that are referenced in `body`
624 fn vars_used_in_body(ctx: &AssistContext, body: &FunctionBody) -> Vec<Local> {
625 // FIXME: currently usages inside macros are not found
627 .filter_map(ast::NameRef::cast)
628 .filter_map(|name_ref| NameRefClass::classify(&ctx.sema, &name_ref))
629 .map(|name_kind| name_kind.referenced(ctx.db()))
630 .filter_map(|definition| match definition {
631 Definition::Local(local) => Some(local),
638 /// find `self` param, that was not defined inside `body`
640 /// It should skip `self` params from impls inside `body`
641 fn self_param_from_usages(
644 vars_used_in_body: &[Local],
645 ) -> Option<(Local, ast::SelfParam)> {
646 let mut iter = vars_used_in_body
648 .filter(|var| var.is_self(ctx.db()))
649 .map(|var| (var, var.source(ctx.db())))
650 .filter(|(_, src)| is_defined_before(ctx, body, src))
651 .filter_map(|(&node, src)| match src.value {
652 Either::Right(it) => Some((node, it)),
654 stdx::never!(false, "Local::is_self returned true, but source is IdentPat");
659 let self_param = iter.next();
661 iter.next().is_none(),
662 "body references two different self params, both defined outside"
668 /// find variables that should be extracted as params
670 /// Computes additional info that affects param type and mutability
671 fn extracted_function_params(
674 vars_used_in_body: &[Local],
678 .filter(|var| !var.is_self(ctx.db()))
679 .map(|node| (node, node.source(ctx.db())))
680 .filter(|(_, src)| is_defined_before(ctx, body, src))
681 .filter_map(|(&node, src)| {
682 if src.value.is_left() {
685 stdx::never!(false, "Local::is_self returned false, but source is SelfParam");
690 let usages = LocalUsages::find(ctx, var);
691 let ty = var.ty(ctx.db());
692 let is_copy = ty.is_copy(ctx.db());
696 has_usages_afterwards: has_usages_after_body(&usages, body),
697 has_mut_inside_body: has_exclusive_usages(ctx, &usages, body),
704 fn has_usages_after_body(usages: &LocalUsages, body: &FunctionBody) -> bool {
705 usages.iter().any(|reference| body.preceedes_range(reference.range))
708 /// checks if relevant var is used with `&mut` access inside body
709 fn has_exclusive_usages(ctx: &AssistContext, usages: &LocalUsages, body: &FunctionBody) -> bool {
712 .filter(|reference| body.contains_range(reference.range))
713 .any(|reference| reference_is_exclusive(reference, body, ctx))
716 /// checks if this reference requires `&mut` access inside body
717 fn reference_is_exclusive(
718 reference: &FileReference,
722 // we directly modify variable with set: `n = 0`, `n += 1`
723 if reference.access == Some(ReferenceAccess::Write) {
727 // we take `&mut` reference to variable: `&mut v`
728 let path = match path_element_of_reference(body, reference) {
730 None => return false,
733 expr_require_exclusive_access(ctx, &path).unwrap_or(false)
736 /// checks if this expr requires `&mut` access, recurses on field access
737 fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> {
738 let parent = expr.syntax().parent()?;
740 if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) {
741 if bin_expr.op_kind()?.is_assignment() {
742 return Some(bin_expr.lhs()?.syntax() == expr.syntax());
747 if let Some(ref_expr) = ast::RefExpr::cast(parent.clone()) {
748 return Some(ref_expr.mut_token().is_some());
751 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
752 let func = ctx.sema.resolve_method_call(&method_call)?;
753 let self_param = func.self_param(ctx.db())?;
754 let access = self_param.access(ctx.db());
756 return Some(matches!(access, hir::Access::Exclusive));
759 if let Some(field) = ast::FieldExpr::cast(parent) {
760 return expr_require_exclusive_access(ctx, &field.into());
766 /// Container of local varaible usages
768 /// Semanticall same as `UsageSearchResult`, but provides more convenient interface
769 struct LocalUsages(ide_db::search::UsageSearchResult);
772 fn find(ctx: &AssistContext, var: Local) -> Self {
774 Definition::Local(var)
776 .in_scope(SearchScope::single_file(ctx.frange.file_id))
781 fn iter(&self) -> impl Iterator<Item = &FileReference> + '_ {
782 self.0.iter().flat_map(|(_, rs)| rs.iter())
786 trait HasTokenAtOffset {
787 fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken>;
790 impl HasTokenAtOffset for SyntaxNode {
791 fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
792 SyntaxNode::token_at_offset(&self, offset)
796 /// find relevant `ast::PathExpr` for reference
800 /// `node` must cover `reference`, that is `node.text_range().contains_range(reference.range)`
801 fn path_element_of_reference(
802 node: &dyn HasTokenAtOffset,
803 reference: &FileReference,
804 ) -> Option<ast::Expr> {
805 let token = node.token_at_offset(reference.range.start()).right_biased().or_else(|| {
806 stdx::never!(false, "cannot find token at variable usage: {:?}", reference);
809 let path = token.ancestors().find_map(ast::Expr::cast).or_else(|| {
810 stdx::never!(false, "cannot find path parent of variable usage: {:?}", token);
813 stdx::always!(matches!(path, ast::Expr::PathExpr(_)));
817 /// list local variables defined inside `body`
818 fn vars_defined_in_body(body: &FunctionBody, ctx: &AssistContext) -> Vec<Local> {
819 // FIXME: this doesn't work well with macros
820 // see https://github.com/rust-analyzer/rust-analyzer/pull/7535#discussion_r570048550
822 .filter_map(ast::IdentPat::cast)
823 .filter_map(|let_stmt| ctx.sema.to_def(&let_stmt))
828 /// list local variables defined inside `body` that should be returned from extracted function
829 fn vars_defined_in_body_and_outlive(ctx: &AssistContext, body: &FunctionBody) -> Vec<Local> {
830 let mut vars_defined_in_body = vars_defined_in_body(&body, ctx);
831 vars_defined_in_body.retain(|var| var_outlives_body(ctx, body, var));
835 /// checks if the relevant local was defined before(outside of) body
836 fn is_defined_before(
839 src: &hir::InFile<Either<ast::IdentPat, ast::SelfParam>>,
841 src.file_id.original_file(ctx.db()) == ctx.frange.file_id
842 && !body.contains_node(&either_syntax(&src.value))
845 fn either_syntax(value: &Either<ast::IdentPat, ast::SelfParam>) -> &SyntaxNode {
847 Either::Left(pat) => pat.syntax(),
848 Either::Right(it) => it.syntax(),
852 /// checks if local variable is used after(outside of) body
853 fn var_outlives_body(ctx: &AssistContext, body: &FunctionBody, var: &Local) -> bool {
854 let usages = LocalUsages::find(ctx, *var);
855 let has_usages = usages.iter().any(|reference| body.preceedes_range(reference.range));
859 fn body_return_ty(ctx: &AssistContext, body: &FunctionBody) -> Option<RetType> {
860 match body.tail_expr() {
862 let ty = ctx.sema.type_of_expr(&expr)?;
863 Some(RetType::Expr(ty))
865 None => Some(RetType::Stmt),
868 /// Where to put extracted function definition
871 /// Extract free function and put right after current top-level function
873 /// Extract method and put right after current function in the impl-block
877 /// find where to put extracted function definition
879 /// Function should be put right after returned node
880 fn scope_for_fn_insertion(body: &FunctionBody, anchor: Anchor) -> Option<SyntaxNode> {
882 FunctionBody::Expr(e) => scope_for_fn_insertion_node(e.syntax(), anchor),
883 FunctionBody::Span { parent, .. } => scope_for_fn_insertion_node(parent.syntax(), anchor),
887 fn scope_for_fn_insertion_node(node: &SyntaxNode, anchor: Anchor) -> Option<SyntaxNode> {
888 let mut ancestors = node.ancestors().peekable();
889 let mut last_ancestor = None;
890 while let Some(next_ancestor) = ancestors.next() {
891 match next_ancestor.kind() {
892 SyntaxKind::SOURCE_FILE => break,
893 SyntaxKind::ITEM_LIST => {
894 if !matches!(anchor, Anchor::Freestanding) {
897 if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::MODULE) {
901 SyntaxKind::ASSOC_ITEM_LIST => {
902 if !matches!(anchor, Anchor::Method) {
905 if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::IMPL) {
911 last_ancestor = Some(next_ancestor);
916 fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String {
917 let ret_ty = fun.return_type(ctx);
919 let args = fun.params.iter().map(|param| param.to_arg(ctx));
920 let args = make::arg_list(args);
921 let call_expr = if fun.self_param.is_some() {
922 let self_arg = make::expr_path(make_path_from_text("self"));
923 make::expr_method_call(self_arg, &fun.name, args)
925 let func = make::expr_path(make_path_from_text(&fun.name));
926 make::expr_call(func, args)
929 let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
931 let expr = handler.make_call_expr(call_expr).indent(indent);
933 let mut buf = String::new();
934 match fun.vars_defined_in_body_and_outlive.as_slice() {
936 [var] => format_to!(buf, "let {} = ", var.name(ctx.db()).unwrap()),
938 buf.push_str("let (");
939 format_to!(buf, "{}", v0.name(ctx.db()).unwrap());
941 format_to!(buf, ", {}", var.name(ctx.db()).unwrap());
943 buf.push_str(") = ");
946 format_to!(buf, "{}", expr);
947 if fun.ret_ty.is_unit()
948 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like())
957 Try { kind: TryKind },
958 If { action: FlowKind },
959 IfOption { action: FlowKind },
960 MatchOption { none: FlowKind },
961 MatchResult { err: FlowKind },
965 fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler {
966 match &fun.control_flow.kind {
967 None => FlowHandler::None,
969 let action = flow_kind.clone();
970 if *ret_ty == FunType::Unit {
972 FlowKind::Return | FlowKind::Break | FlowKind::Continue => {
973 FlowHandler::If { action }
975 FlowKind::ReturnValue(_) | FlowKind::BreakValue(_) => {
976 FlowHandler::IfOption { action }
978 FlowKind::Try { kind } | FlowKind::TryReturn { kind, .. } => {
979 FlowHandler::Try { kind: kind.clone() }
984 FlowKind::Return | FlowKind::Break | FlowKind::Continue => {
985 FlowHandler::MatchOption { none: action }
987 FlowKind::ReturnValue(_) | FlowKind::BreakValue(_) => {
988 FlowHandler::MatchResult { err: action }
990 FlowKind::Try { kind } | FlowKind::TryReturn { kind, .. } => {
991 FlowHandler::Try { kind: kind.clone() }
999 fn make_call_expr(&self, call_expr: ast::Expr) -> ast::Expr {
1001 FlowHandler::None => call_expr,
1002 FlowHandler::Try { kind: _ } => make::expr_try(call_expr),
1003 FlowHandler::If { action } => {
1004 let action = action.make_result_handler(None);
1005 let stmt = make::expr_stmt(action);
1006 let block = make::block_expr(iter::once(stmt.into()), None);
1007 let condition = make::condition(call_expr, None);
1008 make::expr_if(condition, block, None)
1010 FlowHandler::IfOption { action } => {
1011 let path = make_path_from_text("Some");
1012 let value_pat = make::ident_pat(make::name("value"));
1013 let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
1014 let cond = make::condition(call_expr, Some(pattern.into()));
1015 let value = make::expr_path(make_path_from_text("value"));
1016 let action_expr = action.make_result_handler(Some(value));
1017 let action_stmt = make::expr_stmt(action_expr);
1018 let then = make::block_expr(iter::once(action_stmt.into()), None);
1019 make::expr_if(cond, then, None)
1021 FlowHandler::MatchOption { none } => {
1022 let some_name = "value";
1025 let path = make_path_from_text("Some");
1026 let value_pat = make::ident_pat(make::name(some_name));
1027 let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
1028 let value = make::expr_path(make_path_from_text(some_name));
1029 make::match_arm(iter::once(pat.into()), value)
1032 let path = make_path_from_text("None");
1033 let pat = make::path_pat(path);
1034 make::match_arm(iter::once(pat), none.make_result_handler(None))
1036 let arms = make::match_arm_list(vec![some_arm, none_arm]);
1037 make::expr_match(call_expr, arms)
1039 FlowHandler::MatchResult { err } => {
1040 let ok_name = "value";
1041 let err_name = "value";
1044 let path = make_path_from_text("Ok");
1045 let value_pat = make::ident_pat(make::name(ok_name));
1046 let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
1047 let value = make::expr_path(make_path_from_text(ok_name));
1048 make::match_arm(iter::once(pat.into()), value)
1051 let path = make_path_from_text("Err");
1052 let value_pat = make::ident_pat(make::name(err_name));
1053 let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
1054 let value = make::expr_path(make_path_from_text(err_name));
1055 make::match_arm(iter::once(pat.into()), err.make_result_handler(Some(value)))
1057 let arms = make::match_arm_list(vec![ok_arm, err_arm]);
1058 make::expr_match(call_expr, arms)
1064 fn make_path_from_text(text: &str) -> ast::Path {
1065 make::path_unqualified(make::path_segment(make::name_ref(text)))
1068 fn path_expr_from_local(ctx: &AssistContext, var: Local) -> ast::Expr {
1069 let name = var.name(ctx.db()).unwrap().to_string();
1070 make::expr_path(make_path_from_text(&name))
1074 ctx: &AssistContext,
1075 module: hir::Module,
1077 old_indent: IndentLevel,
1078 new_indent: IndentLevel,
1080 let mut fn_def = String::new();
1081 let params = make_param_list(ctx, module, fun);
1082 let ret_ty = make_ret_ty(ctx, module, fun);
1083 let body = make_body(ctx, old_indent, new_indent, fun);
1084 match ctx.config.snippet_cap {
1085 Some(_) => format_to!(fn_def, "\n\n{}fn $0{}{}", new_indent, fun.name, params),
1086 None => format_to!(fn_def, "\n\n{}fn {}{}", new_indent, fun.name, params),
1088 if let Some(ret_ty) = ret_ty {
1089 format_to!(fn_def, " {}", ret_ty);
1091 format_to!(fn_def, " {}", body);
1096 fn make_param_list(ctx: &AssistContext, module: hir::Module, fun: &Function) -> ast::ParamList {
1097 let self_param = fun.self_param.clone();
1098 let params = fun.params.iter().map(|param| param.to_param(ctx, module));
1099 make::param_list(self_param, params)
1103 fn make_ty(&self, ctx: &AssistContext, module: hir::Module) -> ast::Type {
1105 FunType::Unit => make::ty_unit(),
1106 FunType::Single(ty) => make_ty(ty, ctx, module),
1107 FunType::Tuple(types) => match types.as_slice() {
1109 stdx::never!("tuple type with 0 elements");
1113 stdx::never!("tuple type with 1 element");
1114 make_ty(ty, ctx, module)
1117 let types = types.iter().map(|ty| make_ty(ty, ctx, module));
1118 make::ty_tuple(types)
1125 fn make_ret_ty(ctx: &AssistContext, module: hir::Module, fun: &Function) -> Option<ast::RetType> {
1126 let fun_ty = fun.return_type(ctx);
1127 let handler = FlowHandler::from_ret_ty(fun, &fun_ty);
1128 let ret_ty = match &handler {
1129 FlowHandler::None => {
1130 if matches!(fun_ty, FunType::Unit) {
1133 fun_ty.make_ty(ctx, module)
1135 FlowHandler::Try { kind: TryKind::Option } => {
1136 make::ty_generic(make::name_ref("Option"), iter::once(fun_ty.make_ty(ctx, module)))
1138 FlowHandler::Try { kind: TryKind::Result { ty: parent_ret_ty } } => {
1139 let handler_ty = parent_ret_ty
1142 .map(|ty| make_ty(&ty, ctx, module))
1143 .unwrap_or_else(make::ty_unit);
1145 make::name_ref("Result"),
1146 vec![fun_ty.make_ty(ctx, module), handler_ty],
1149 FlowHandler::If { .. } => make::ty("bool"),
1150 FlowHandler::IfOption { action } => {
1151 let handler_ty = action
1153 .map(|ty| make_ty(&ty, ctx, module))
1154 .unwrap_or_else(make::ty_unit);
1155 make::ty_generic(make::name_ref("Option"), iter::once(handler_ty))
1157 FlowHandler::MatchOption { .. } => {
1158 make::ty_generic(make::name_ref("Option"), iter::once(fun_ty.make_ty(ctx, module)))
1160 FlowHandler::MatchResult { err } => {
1162 err.expr_ty(ctx).map(|ty| make_ty(&ty, ctx, module)).unwrap_or_else(make::ty_unit);
1164 make::name_ref("Result"),
1165 vec![fun_ty.make_ty(ctx, module), handler_ty],
1169 Some(make::ret_type(ret_ty))
1173 ctx: &AssistContext,
1174 old_indent: IndentLevel,
1175 new_indent: IndentLevel,
1177 ) -> ast::BlockExpr {
1178 let ret_ty = fun.return_type(ctx);
1179 let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
1180 let block = match &fun.body {
1181 FunctionBody::Expr(expr) => {
1182 let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
1183 let expr = ast::Expr::cast(expr).unwrap();
1184 let expr = expr.dedent(old_indent).indent(IndentLevel(1));
1186 make::block_expr(Vec::new(), Some(expr))
1188 FunctionBody::Span { parent, text_range } => {
1189 let mut elements: Vec<_> = parent
1192 .filter(|it| text_range.contains_range(it.text_range()))
1193 .map(|it| rewrite_body_segment(ctx, &fun.params, &handler, &it))
1196 let mut tail_expr = match elements.pop() {
1197 Some(node) => ast::Expr::cast(node.clone()).or_else(|| {
1198 elements.push(node);
1204 if tail_expr.is_none() {
1205 match fun.vars_defined_in_body_and_outlive.as_slice() {
1208 tail_expr = Some(path_expr_from_local(ctx, *var));
1211 let exprs = vars.iter().map(|var| path_expr_from_local(ctx, *var));
1212 let expr = make::expr_tuple(exprs);
1213 tail_expr = Some(expr);
1218 let elements = elements.into_iter().filter_map(|node| match ast::Stmt::cast(node) {
1219 Some(stmt) => Some(stmt),
1221 stdx::never!("block contains non-statement");
1226 let body_indent = IndentLevel(1);
1227 let elements = elements.map(|stmt| stmt.dedent(old_indent).indent(body_indent));
1228 let tail_expr = tail_expr.map(|expr| expr.dedent(old_indent).indent(body_indent));
1230 make::block_expr(elements, tail_expr)
1234 let block = match &handler {
1235 FlowHandler::None => block,
1236 FlowHandler::Try { kind } => {
1237 let block = with_default_tail_expr(block, make::expr_unit());
1238 map_tail_expr(block, |tail_expr| {
1239 let constructor = match kind {
1240 TryKind::Option => "Some",
1241 TryKind::Result { .. } => "Ok",
1243 let func = make::expr_path(make_path_from_text(constructor));
1244 let args = make::arg_list(iter::once(tail_expr));
1245 make::expr_call(func, args)
1248 FlowHandler::If { .. } => {
1249 let lit_false = ast::Literal::cast(make::tokens::literal("false").parent()).unwrap();
1250 with_tail_expr(block, lit_false.into())
1252 FlowHandler::IfOption { .. } => {
1253 let none = make::expr_path(make_path_from_text("None"));
1254 with_tail_expr(block, none)
1256 FlowHandler::MatchOption { .. } => map_tail_expr(block, |tail_expr| {
1257 let some = make::expr_path(make_path_from_text("Some"));
1258 let args = make::arg_list(iter::once(tail_expr));
1259 make::expr_call(some, args)
1261 FlowHandler::MatchResult { .. } => map_tail_expr(block, |tail_expr| {
1262 let ok = make::expr_path(make_path_from_text("Ok"));
1263 let args = make::arg_list(iter::once(tail_expr));
1264 make::expr_call(ok, args)
1268 block.indent(new_indent)
1271 fn map_tail_expr(block: ast::BlockExpr, f: impl FnOnce(ast::Expr) -> ast::Expr) -> ast::BlockExpr {
1272 let tail_expr = match block.tail_expr() {
1273 Some(tail_expr) => tail_expr,
1274 None => return block,
1276 make::block_expr(block.statements(), Some(f(tail_expr)))
1279 fn with_default_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr {
1280 match block.tail_expr() {
1282 None => make::block_expr(block.statements(), Some(tail_expr)),
1286 fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr {
1287 let stmt_tail = block.tail_expr().map(|expr| make::expr_stmt(expr).into());
1288 let stmts = block.statements().chain(stmt_tail);
1289 make::block_expr(stmts, Some(tail_expr))
1292 fn format_type(ty: &hir::Type, ctx: &AssistContext, module: hir::Module) -> String {
1293 ty.display_source_code(ctx.db(), module.into()).ok().unwrap_or_else(|| "()".to_string())
1296 fn make_ty(ty: &hir::Type, ctx: &AssistContext, module: hir::Module) -> ast::Type {
1297 let ty_str = format_type(ty, ctx, module);
1301 fn rewrite_body_segment(
1302 ctx: &AssistContext,
1304 handler: &FlowHandler,
1305 syntax: &SyntaxNode,
1307 let syntax = fix_param_usages(ctx, params, syntax);
1308 update_external_control_flow(handler, &syntax)
1311 /// change all usages to account for added `&`/`&mut` for some params
1312 fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode {
1313 let mut rewriter = SyntaxRewriter::default();
1314 for param in params {
1315 if !param.kind().is_ref() {
1319 let usages = LocalUsages::find(ctx, param.var);
1322 .filter(|reference| syntax.text_range().contains_range(reference.range))
1323 .filter_map(|reference| path_element_of_reference(syntax, reference));
1324 for path in usages {
1325 match path.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
1326 Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => {
1329 Some(ast::Expr::RefExpr(node))
1330 if param.kind() == ParamKind::MutRef && node.mut_token().is_some() =>
1332 rewriter.replace_ast(&node.clone().into(), &node.expr().unwrap());
1334 Some(ast::Expr::RefExpr(node))
1335 if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() =>
1337 rewriter.replace_ast(&node.clone().into(), &node.expr().unwrap());
1340 rewriter.replace_ast(&path, &make::expr_prefix(T![*], path.clone()));
1346 rewriter.rewrite(syntax)
1349 fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode {
1350 let mut rewriter = SyntaxRewriter::default();
1352 let mut nested_loop = None;
1353 let mut nested_scope = None;
1354 for event in syntax.preorder() {
1355 let node = match event {
1356 WalkEvent::Enter(e) => {
1358 SyntaxKind::LOOP_EXPR | SyntaxKind::WHILE_EXPR | SyntaxKind::FOR_EXPR => {
1359 if nested_loop.is_none() {
1360 nested_loop = Some(e.clone());
1365 | SyntaxKind::STATIC
1367 | SyntaxKind::MODULE => {
1368 if nested_scope.is_none() {
1369 nested_scope = Some(e.clone());
1376 WalkEvent::Leave(e) => {
1377 if nested_loop.as_ref() == Some(&e) {
1380 if nested_scope.as_ref() == Some(&e) {
1381 nested_scope = None;
1386 if nested_scope.is_some() {
1389 let expr = match ast::Expr::cast(node) {
1394 ast::Expr::ReturnExpr(return_expr) if nested_scope.is_none() => {
1395 let expr = return_expr.expr();
1396 if let Some(replacement) = make_rewritten_flow(handler, expr) {
1397 rewriter.replace_ast(&return_expr.into(), &replacement);
1400 ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => {
1401 let expr = break_expr.expr();
1402 if let Some(replacement) = make_rewritten_flow(handler, expr) {
1403 rewriter.replace_ast(&break_expr.into(), &replacement);
1406 ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => {
1407 if let Some(replacement) = make_rewritten_flow(handler, None) {
1408 rewriter.replace_ast(&continue_expr.into(), &replacement);
1417 rewriter.rewrite(syntax)
1420 fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> {
1421 let value = match handler {
1422 FlowHandler::None | FlowHandler::Try { .. } => return None,
1423 FlowHandler::If { .. } => {
1424 ast::Literal::cast(make::tokens::literal("true").parent()).unwrap().into()
1426 FlowHandler::IfOption { .. } => {
1427 let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
1428 let args = make::arg_list(iter::once(expr));
1429 make::expr_call(make::expr_path(make_path_from_text("Some")), args)
1431 FlowHandler::MatchOption { .. } => make::expr_path(make_path_from_text("None")),
1432 FlowHandler::MatchResult { .. } => {
1433 let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
1434 let args = make::arg_list(iter::once(expr));
1435 make::expr_call(make::expr_path(make_path_from_text("Err")), args)
1438 Some(make::expr_return(Some(value)))
1443 use crate::tests::{check_assist, check_assist_not_applicable};
1448 fn no_args_from_binary_expr() {
1460 fn $0fun_name() -> i32 {
1467 fn no_args_from_binary_expr_in_module() {
1482 fn $0fun_name() -> i32 {
1490 fn no_args_from_binary_expr_indented() {
1502 fn $0fun_name() -> i32 {
1509 fn no_args_from_stmt_with_last_expr() {
1524 fn $0fun_name() -> i32 {
1532 fn no_args_from_stmt_unit() {
1576 fn no_args_if_else() {
1581 $0if true { 1 } else { 2 }$0
1588 fn $0fun_name() -> i32 {
1589 if true { 1 } else { 2 }
1595 fn no_args_if_let_else() {
1600 $0if let true = false { 1 } else { 2 }$0
1607 fn $0fun_name() -> i32 {
1608 if let true = false { 1 } else { 2 }
1614 fn no_args_match() {
1629 fn $0fun_name() -> i32 {
1639 fn no_args_while() {
1663 $0for v in &[0, 1] { }$0
1671 for v in &[0, 1] { }
1677 fn no_args_from_loop_unit() {
1691 fn $0fun_name() -> ! {
1700 fn no_args_from_loop_with_return() {
1715 fn $0fun_name() -> i32 {
1725 fn no_args_from_match() {
1730 let v: i32 = $0match Some(1) {
1737 let v: i32 = fun_name();
1740 fn $0fun_name() -> i32 {
1750 fn argument_form_expr() {
1764 fn $0fun_name(n: u32) -> u32 {
1771 fn argument_used_twice_form_expr() {
1785 fn $0fun_name(n: u32) -> u32 {
1792 fn two_arguments_form_expr() {
1808 fn $0fun_name(n: u32, m: u32) -> u32 {
1815 fn argument_and_locals() {
1830 fn $0fun_name(n: u32) -> u32 {
1838 fn in_comment_is_not_applicable() {
1839 cov_mark::check!(extract_function_in_comment_is_not_applicable);
1840 check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }");
1844 fn part_of_expr_stmt() {
1856 fn $0fun_name() -> i32 {
1863 fn function_expr() {
1882 fn extract_from_nested() {
1888 let tuple = match x {
1889 true => ($02 + 2$0, true)
1896 let tuple = match x {
1897 true => (fun_name(), true)
1902 fn $0fun_name() -> i32 {
1909 fn param_from_closure() {
1914 let lambda = |x: u32| $0x * 2$0;
1918 let lambda = |x: u32| fun_name(x);
1921 fn $0fun_name(x: u32) -> u32 {
1928 fn extract_return_stmt() {
1940 fn $0fun_name() -> u32 {
1947 fn does_not_add_extra_whitespace() {
1963 fn $0fun_name() -> u32 {
1986 fn $0fun_name() -> i32 {
1998 let v = $00f32 as u32$0;
2005 fn $0fun_name() -> u32 {
2012 fn return_not_applicable() {
2013 check_assist_not_applicable(extract_function, r"fn foo() { $0return$0; } ");
2017 fn method_to_freestanding() {
2024 fn foo(&self) -> i32 {
2032 fn foo(&self) -> i32 {
2037 fn $0fun_name() -> i32 {
2044 fn method_with_reference() {
2048 struct S { f: i32 };
2051 fn foo(&self) -> i32 {
2056 struct S { f: i32 };
2059 fn foo(&self) -> i32 {
2063 fn $0fun_name(&self) -> i32 {
2071 fn method_with_mut() {
2075 struct S { f: i32 };
2083 struct S { f: i32 };
2090 fn $0fun_name(&mut self) {
2098 fn variable_defined_inside_and_used_after_no_ret() {
2110 let k = fun_name(n);
2114 fn $0fun_name(n: i32) -> i32 {
2122 fn two_variables_defined_inside_and_used_after_no_ret() {
2135 let (k, m) = fun_name(n);
2139 fn $0fun_name(n: i32) -> (i32, i32) {
2148 fn nontrivial_patterns_define_variables() {
2152 struct Counter(i32);
2154 $0let Counter(n) = Counter(0);$0
2158 struct Counter(i32);
2164 fn $0fun_name() -> i32 {
2165 let Counter(n) = Counter(0);
2172 fn struct_with_two_fields_pattern_define_variables() {
2176 struct Counter { n: i32, m: i32 };
2178 $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0
2182 struct Counter { n: i32, m: i32 };
2184 let (n, k) = fun_name();
2188 fn $0fun_name() -> (i32, i32) {
2189 let Counter { n, m: k } = Counter { n: 1, m: 2 };
2196 fn mut_var_from_outer_scope() {
2212 fn $0fun_name(n: &mut i32) {
2219 fn mut_field_from_outer_scope() {
2225 let mut c = C { n: 0 };
2232 let mut c = C { n: 0 };
2237 fn $0fun_name(c: &mut C) {
2244 fn mut_nested_field_from_outer_scope() {
2251 let mut c = C { p: P { n: 0 } };
2252 let mut v = C { p: P { n: 0 } };
2253 let u = C { p: P { n: 0 } };
2255 let r = &mut v.p.n;$0
2256 let m = c.p.n + v.p.n + u.p.n;
2262 let mut c = C { p: P { n: 0 } };
2263 let mut v = C { p: P { n: 0 } };
2264 let u = C { p: P { n: 0 } };
2265 fun_name(&mut c, &u, &mut v);
2266 let m = c.p.n + v.p.n + u.p.n;
2269 fn $0fun_name(c: &mut C, u: &C, v: &mut C) {
2277 fn mut_param_many_usages_stmt() {
2283 fn succ(&self) -> Self;
2284 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
2287 fn succ(&self) -> Self { *self + 1 }
2305 fn succ(&self) -> Self;
2306 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
2309 fn succ(&self) -> Self { *self + 1 }
2317 fn $0fun_name(n: &mut i32) {
2332 fn mut_param_many_usages_expr() {
2338 fn succ(&self) -> Self;
2339 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
2342 fn succ(&self) -> Self { *self + 1 }
2362 fn succ(&self) -> Self;
2363 fn inc(&mut self) -> Self { let v = self.succ(); *self = v; v }
2366 fn succ(&self) -> Self { *self + 1 }
2374 fn $0fun_name(n: &mut i32) {
2391 fn mut_param_by_value() {
2405 fn $0fun_name(mut n: i32) {
2412 fn mut_param_because_of_mut_ref() {
2429 fn $0fun_name(n: &mut i32) {
2437 fn mut_param_by_value_because_of_mut_ref() {
2452 fn $0fun_name(mut n: i32) {
2460 fn mut_method_call() {
2468 fn inc(&mut self) { *self += 1 }
2479 fn inc(&mut self) { *self += 1 }
2486 fn $0fun_name(mut n: i32) {
2493 fn shared_method_call() {
2501 fn succ(&self) { *self + 1 }
2512 fn succ(&self) { *self + 1 }
2519 fn $0fun_name(n: i32) {
2526 fn mut_method_call_with_other_receiver() {
2531 fn inc(&mut self, n: i32);
2534 fn inc(&mut self, n: i32) { *self += n }
2543 fn inc(&mut self, n: i32);
2546 fn inc(&mut self, n: i32) { *self += n }
2553 fn $0fun_name(n: i32) {
2561 fn non_copy_without_usages_after() {
2565 struct Counter(i32);
2571 struct Counter(i32);
2577 fn $0fun_name(c: Counter) {
2584 fn non_copy_used_after() {
2588 struct Counter(i32);
2595 struct Counter(i32);
2602 fn $0fun_name(c: &Counter) {
2609 fn copy_used_after() {
2615 impl Copy for i32 {}
2624 impl Copy for i32 {}
2631 fn $0fun_name(n: i32) {
2638 fn copy_custom_used_after() {
2644 struct Counter(i32);
2645 impl Copy for Counter {}
2654 struct Counter(i32);
2655 impl Copy for Counter {}
2662 fn $0fun_name(c: Counter) {
2669 fn indented_stmts() {
2698 fn indented_stmts_inside_mod() {
2736 #[lang = "None"] None,
2737 #[lang = "Some"] Some(T),
2751 #[lang = "None"] None,
2752 #[lang = "Some"] Some(T),
2758 let k = match fun_name(n) {
2759 Some(value) => value,
2766 fn $0fun_name(n: i32) -> Option<i32> {
2776 fn return_to_parent() {
2782 impl Copy for i32 {}
2784 #[lang = "Ok"] Ok(T),
2785 #[lang = "Err"] Err(E),
2798 impl Copy for i32 {}
2800 #[lang = "Ok"] Ok(T),
2801 #[lang = "Err"] Err(E),
2806 let k = match fun_name(n) {
2808 Err(value) => return value,
2813 fn $0fun_name(n: i32) -> Result<i32, i64> {
2823 fn break_and_continue() {
2824 cov_mark::check!(external_control_flow_break_and_continue);
2825 check_assist_not_applicable(
2843 fn return_and_break() {
2844 cov_mark::check!(external_control_flow_return_and_bc);
2845 check_assist_not_applicable(
2863 fn break_loop_with_if() {
2880 if fun_name(&mut n) {
2887 fn $0fun_name(n: &mut i32) -> bool {
2897 fn break_loop_nested() {
2922 fn $0fun_name(n: i32) -> bool {
2933 fn return_from_nested_loop() {
2953 let m = match fun_name() {
2954 Some(value) => value,
2961 fn $0fun_name() -> Option<i32> {
2973 fn break_from_nested_loop() {
2997 fn $0fun_name() -> i32 {
3009 fn break_from_nested_and_outer_loops() {
3031 let m = match fun_name() {
3032 Some(value) => value,
3039 fn $0fun_name() -> Option<i32> {
3054 fn return_from_nested_fn() {
3078 fn $0fun_name() -> i32 {
3090 fn break_with_value() {
3109 if let Some(value) = fun_name() {
3116 fn $0fun_name() -> Option<i32> {
3128 fn break_with_value_and_return() {
3148 let m = match fun_name() {
3150 Err(value) => break value,
3156 fn $0fun_name() -> Result<i32, i64> {
3172 enum Option<T> { None, Some(T), }
3174 fn bar() -> Option<i32> { None }
3175 fn foo() -> Option<()> {
3183 enum Option<T> { None, Some(T), }
3185 fn bar() -> Option<i32> { None }
3186 fn foo() -> Option<()> {
3188 let m = fun_name()?;
3193 fn $0fun_name() -> Option<i32> {
3202 fn try_option_unit() {
3206 enum Option<T> { None, Some(T), }
3208 fn foo() -> Option<()> {
3216 enum Option<T> { None, Some(T), }
3218 fn foo() -> Option<()> {
3225 fn $0fun_name() -> Option<()> {
3238 enum Result<T, E> { Ok(T), Err(E), }
3240 fn foo() -> Result<(), i64> {
3248 enum Result<T, E> { Ok(T), Err(E), }
3250 fn foo() -> Result<(), i64> {
3252 let m = fun_name()?;
3257 fn $0fun_name() -> Result<i32, i64> {
3266 fn try_option_with_return() {
3270 enum Option<T> { None, Some(T) }
3272 fn foo() -> Option<()> {
3283 enum Option<T> { None, Some(T) }
3285 fn foo() -> Option<()> {
3287 let m = fun_name()?;
3292 fn $0fun_name() -> Option<i32> {
3304 fn try_result_with_return() {
3308 enum Result<T, E> { Ok(T), Err(E), }
3310 fn foo() -> Result<(), i64> {
3321 enum Result<T, E> { Ok(T), Err(E), }
3323 fn foo() -> Result<(), i64> {
3325 let m = fun_name()?;
3330 fn $0fun_name() -> Result<i32, i64> {
3342 fn try_and_break() {
3343 cov_mark::check!(external_control_flow_try_and_bc);
3344 check_assist_not_applicable(
3347 enum Option<T> { None, Some(T) }
3349 fn foo() -> Option<()> {
3364 fn try_and_return_ok() {
3365 cov_mark::check!(external_control_flow_try_and_return_non_err);
3366 check_assist_not_applicable(
3369 enum Result<T, E> { Ok(T), Err(E), }
3371 fn foo() -> Result<(), i64> {