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.rs146
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,