From a2bcad15d5e765163b6577195efd5d63d0cbf656 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 2 Oct 2025 13:35:35 +0800 Subject: [PATCH] Add ide-assist: flip_else_if Flips two if-else-if branches. Example --- ```rust fn foo() { let n = if cond1 { 2 } else$0 if cond2 { 3 } else { 0 }; } ``` -> ```rust fn foo() { let n = if cond2 { 3 } else if cond1 { 2 } else { 0 }; } ``` --- .../ide-assists/src/handlers/flip_else_if.rs | 99 +++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 17 ++++ 3 files changed, 118 insertions(+) create mode 100644 crates/ide-assists/src/handlers/flip_else_if.rs diff --git a/crates/ide-assists/src/handlers/flip_else_if.rs b/crates/ide-assists/src/handlers/flip_else_if.rs new file mode 100644 index 000000000000..6fb07856cb37 --- /dev/null +++ b/crates/ide-assists/src/handlers/flip_else_if.rs @@ -0,0 +1,99 @@ +use syntax::{AstNode, T, ast, syntax_editor::SyntaxEditor}; + +use crate::{AssistContext, AssistId, Assists}; + +// Assist: flip_else_if +// +// Flips two if-else-if branches. +// +// ``` +// fn foo() { +// let n = if cond1 { 2 } else$0 if cond2 { 3 } else { 0 }; +// } +// ``` +// -> +// ``` +// fn foo() { +// let n = if cond2 { 3 } else if cond1 { 2 } else { 0 }; +// } +// ``` +pub(crate) fn flip_else_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let else_kw = ctx.find_token_syntax_at_offset(T![else])?; + let if_expr = ast::IfExpr::cast(else_kw.parent()?)?; + let ast::ElseBranch::IfExpr(else_if) = if_expr.else_branch()? else { return None }; + + let (cond, block) = (if_expr.condition()?, if_expr.then_branch()?); + let (else_cond, else_block) = (else_if.condition()?, else_if.then_branch()?); + + let target = else_kw.text_range(); + acc.add(AssistId::refactor_rewrite("flip_else_if"), "Flip if else if", target, |builder| { + let mut edit = builder.make_editor(if_expr.syntax()); + + swap_node(&cond, &else_cond, &mut edit); + swap_node(&block, &else_block, &mut edit); + + builder.add_file_edits(ctx.vfs_file_id(), edit); + }) +} + +fn swap_node(lhs: &impl AstNode, rhs: &impl AstNode, edit: &mut SyntaxEditor) { + edit.replace(lhs.syntax(), rhs.syntax()); + edit.replace(rhs.syntax(), lhs.syntax()); +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn not_applicable_without_else_keyword() { + check_assist_not_applicable( + flip_else_if, + r#" + fn foo() { + let n = if cond1 { 2 } else if$0 cond2 { 3 } else { 0 }; + } + "#, + ); + + check_assist_not_applicable( + flip_else_if, + r#" + fn foo() { + let n = if$0 cond1 { 2 } else if cond2 { 3 } else { 0 }; + } + "#, + ); + } + + #[test] + fn without_else_branch() { + check_assist( + flip_else_if, + r#" + fn foo() { + if cond1 { 2 } $0else if cond2 { 3 }; + } + "#, + r#" + fn foo() { + if cond2 { 3 } else if cond1 { 2 }; + } + "#, + ); + } + + #[test] + fn not_applicable_else_block_branch() { + check_assist_not_applicable( + flip_else_if, + r#" + fn foo() { + let n = if cond1 { 2 } else$0 { 3 }; + } + "#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 4682c0473238..ecc9065150f8 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -151,6 +151,7 @@ mod handlers { mod fix_visibility; mod flip_binexpr; mod flip_comma; + mod flip_else_if; mod flip_or_pattern; mod flip_trait_bound; mod generate_constant; @@ -284,6 +285,7 @@ mod handlers { fix_visibility::fix_visibility, flip_binexpr::flip_binexpr, flip_comma::flip_comma, + flip_else_if::flip_else_if, flip_or_pattern::flip_or_pattern, flip_trait_bound::flip_trait_bound, generate_constant::generate_constant, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index e7f91ff3fbc1..ea1c789b0c60 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1315,6 +1315,23 @@ fn main() { ) } +#[test] +fn doctest_flip_else_if() { + check_doc_test( + "flip_else_if", + r#####" +fn foo() { + let n = if cond1 { 2 } else$0 if cond2 { 3 } else { 0 }; +} +"#####, + r#####" +fn foo() { + let n = if cond2 { 3 } else if cond1 { 2 } else { 0 }; +} +"#####, + ) +} + #[test] fn doctest_flip_or_pattern() { check_doc_test(