diff --git a/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/crates/ide-assists/src/handlers/unmerge_match_arm.rs index 7b0f2dc65a78..08cc32c9c0c0 100644 --- a/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -104,6 +104,70 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O ) } +// Assist: unmerge_to_guarded_arm +// +// Unmerge into guarded match arm. +// +// ``` +// enum Kind { Num(u32) } +// +// fn handle(kind: Kind) { +// match kind { +// Kind::Num(n) $0=> foo(n), +// } +// } +// ``` +// -> +// ``` +// enum Kind { Num(u32) } +// +// fn handle(kind: Kind) { +// match kind { +// Kind::Num(n) if $0 => foo(n), +// Kind::Num(n) => foo(n), +// } +// } +// ``` +pub(crate) fn unmerge_to_guarded_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let arrow_token = ctx.find_token_syntax_at_offset(T![=>])?; + let match_arm = ast::MatchArm::cast(arrow_token.parent()?)?; + + if match_arm.guard().is_some() { + return None; + } + + acc.add( + AssistId::refactor_rewrite("unmerge_to_guarded_arm"), + "Unmerge to guarded match arm", + match_arm.syntax().text_range(), + |edit| { + let make = SyntaxFactory::without_mappings(); + let mut editor = edit.make_editor(match_arm.syntax()); + + let guard = vec![ + make.token(T![if]).into(), + make.whitespace(" ").into(), + make.whitespace(" ").into(), + ]; + if let Some(cap) = ctx.config.snippet_cap { + editor.add_annotation(&guard[2], edit.make_tabstop_before(cap)); + } + editor.insert_all(Position::before(arrow_token), guard); + + let new_arm = match_arm.syntax().clone_for_update(); + editor.insert(Position::after(match_arm.syntax()), &new_arm); + + if let Some(prev) = new_arm.prev_sibling_or_token() + && prev.kind() == SyntaxKind::WHITESPACE + { + editor.insert(Position::after(match_arm.syntax()), prev); + } + + edit.add_file_edits(ctx.vfs_file_id(), editor); + }, + ) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -278,6 +342,46 @@ fn main() { X::B => {} } } +"#, + ); + } + + #[test] + fn unmerge_to_guarded_arm_with_block() { + check_assist( + unmerge_to_guarded_arm, + r#" +fn main() { + match () { + () $0=> { + foo() + } + }; +}"#, + r#" +fn main() { + match () { + () if $0 => { + foo() + } + () => { + foo() + } + }; +}"#, + ); + } + + #[test] + fn unmerge_to_guarded_arm_guarded() { + check_assist_not_applicable( + unmerge_to_guarded_arm, + r#" +fn main() { + match () { + () if true $0=> {} + }; +} "#, ); } diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index ca468905fb6b..f184a07ca5c2 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -376,6 +376,7 @@ mod handlers { toggle_ignore::toggle_ignore, toggle_macro_delimiter::toggle_macro_delimiter, unmerge_match_arm::unmerge_match_arm, + unmerge_match_arm::unmerge_to_guarded_arm, unmerge_imports::unmerge_imports, unnecessary_async::unnecessary_async, unqualify_method_call::unqualify_method_call, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 7eef257b95f1..733938f8172e 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -3653,6 +3653,32 @@ fn handle(action: Action) { ) } +#[test] +fn doctest_unmerge_to_guarded_arm() { + check_doc_test( + "unmerge_to_guarded_arm", + r#####" +enum Kind { Num(u32) } + +fn handle(kind: Kind) { + match kind { + Kind::Num(n) $0=> foo(n), + } +} +"#####, + r#####" +enum Kind { Num(u32) } + +fn handle(kind: Kind) { + match kind { + Kind::Num(n) if $0 => foo(n), + Kind::Num(n) => foo(n), + } +} +"#####, + ) +} + #[test] fn doctest_unnecessary_async() { check_doc_test( diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index dba39204e32e..eeab75b35491 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -1355,7 +1355,7 @@ pub mod tokens { pub(super) static SOURCE_FILE: LazyLock> = LazyLock::new(|| { SourceFile::parse( - "use crate::foo; const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, async { let _ @ [] }, while loop {} {})\n;\n\nunsafe impl A for B where: {}", + "use crate::foo; const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, async { let _ @ [] }, while loop {} {}, if false { false } else { true })\n;\n\nunsafe impl A for B where: {}", Edition::CURRENT, ) });