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