Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_assists/src/handlers/extract_function.rs')
| -rw-r--r-- | crates/ide_assists/src/handlers/extract_function.rs | 146 |
1 files changed, 128 insertions, 18 deletions
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index e48a1cd9ef..8352774be4 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs @@ -287,10 +287,10 @@ enum FlowKind { Try { kind: TryKind, }, - /// Break with value (`break $expr;`) - Break(Option<ast::Expr>), - /// Continue - Continue, + /// Break with label and value (`break 'label $expr;`) + Break(Option<ast::Lifetime>, Option<ast::Expr>), + /// Continue with label (`continue 'label;`) + Continue(Option<ast::Lifetime>), } #[derive(Debug, Clone)] @@ -433,21 +433,21 @@ impl FlowKind { fn make_result_handler(&self, expr: Option<ast::Expr>) -> ast::Expr { match self { FlowKind::Return(_) => make::expr_return(expr), - FlowKind::Break(_) => make::expr_break(expr), + FlowKind::Break(label, _) => make::expr_break(label.clone(), expr), FlowKind::Try { .. } => { stdx::never!("cannot have result handler with try"); expr.unwrap_or_else(|| make::expr_return(None)) } - FlowKind::Continue => { + FlowKind::Continue(label) => { stdx::always!(expr.is_none(), "continue with value is not possible"); - make::expr_continue() + make::expr_continue(label.clone()) } } } fn expr_ty(&self, ctx: &AssistContext) -> Option<hir::Type> { match self { - FlowKind::Return(Some(expr)) | FlowKind::Break(Some(expr)) => { + FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => { ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted) } FlowKind::Try { .. } => { @@ -839,8 +839,8 @@ impl FunctionBody { cov_mark::hit!(external_control_flow_break_and_continue); return None; } - (None, None, Some(b), None) => Some(FlowKind::Break(b.expr())), - (None, None, None, Some(_)) => Some(FlowKind::Continue), + (None, None, Some(b), None) => Some(FlowKind::Break(b.lifetime(), b.expr())), + (None, None, None, Some(c)) => Some(FlowKind::Continue(c.lifetime())), (None, None, None, None) => None, }; @@ -1185,20 +1185,20 @@ impl FlowHandler { let action = flow_kind.clone(); if *ret_ty == FunType::Unit { match flow_kind { - FlowKind::Return(None) | FlowKind::Break(None) | FlowKind::Continue => { - FlowHandler::If { action } - } - FlowKind::Return(_) | FlowKind::Break(_) => { + FlowKind::Return(None) + | FlowKind::Break(_, None) + | FlowKind::Continue(_) => FlowHandler::If { action }, + FlowKind::Return(_) | FlowKind::Break(_, _) => { FlowHandler::IfOption { action } } FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() }, } } else { match flow_kind { - FlowKind::Return(None) | FlowKind::Break(None) | FlowKind::Continue => { - FlowHandler::MatchOption { none: action } - } - FlowKind::Return(_) | FlowKind::Break(_) => { + FlowKind::Return(None) + | FlowKind::Break(_, None) + | FlowKind::Continue(_) => FlowHandler::MatchOption { none: action }, + FlowKind::Return(_) | FlowKind::Break(_, _) => { FlowHandler::MatchResult { err: action } } FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() }, @@ -3405,6 +3405,76 @@ fn $0fun_name(n: i32) -> ControlFlow<()> { } #[test] + fn break_loop_nested_labeled() { + check_assist( + extract_function, + r#" +//- minicore: try +fn foo() { + 'bar: loop { + loop { + $0break 'bar;$0 + } + } +} +"#, + r#" +use core::ops::ControlFlow; + +fn foo() { + 'bar: loop { + loop { + if let ControlFlow::Break(_) = fun_name() { + break 'bar; + } + } + } +} + +fn $0fun_name() -> ControlFlow<()> { + return ControlFlow::Break(()); + ControlFlow::Continue(()) +} +"#, + ); + } + + #[test] + fn continue_loop_nested_labeled() { + check_assist( + extract_function, + r#" +//- minicore: try +fn foo() { + 'bar: loop { + loop { + $0continue 'bar;$0 + } + } +} +"#, + r#" +use core::ops::ControlFlow; + +fn foo() { + 'bar: loop { + loop { + if let ControlFlow::Break(_) = fun_name() { + continue 'bar; + } + } + } +} + +fn $0fun_name() -> ControlFlow<()> { + return ControlFlow::Break(()); + ControlFlow::Continue(()) +} +"#, + ); + } + + #[test] fn return_from_nested_loop() { check_assist( extract_function, @@ -3609,6 +3679,46 @@ fn $0fun_name() -> Option<i32> { } #[test] + fn break_with_value_and_label() { + check_assist( + extract_function, + r#" +fn foo() -> i32 { + 'bar: loop { + let n = 1; + $0let k = 1; + if k == 42 { + break 'bar 4; + } + let m = k + 1;$0 + let h = 1; + } +} +"#, + r#" +fn foo() -> i32 { + 'bar: loop { + let n = 1; + if let Some(value) = fun_name() { + break 'bar value; + } + let h = 1; + } +} + +fn $0fun_name() -> Option<i32> { + let k = 1; + if k == 42 { + return Some(4); + } + let m = k + 1; + None +} +"#, + ); + } + + #[test] fn break_with_value_and_return() { check_assist( extract_function, |