From 88595fe7f72b976801cc30344d1073355fa520bc Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 26 Jan 2026 01:46:13 +0800 Subject: [PATCH] Fix semicolon for toggle_macro_delimiter Example --- ```rust macro_rules! sth { () => {}; } sth!$0{ } ``` (old test `sth!{};` is a syntax error in item place) **Before this PR** ```rust macro_rules! sth { () => {}; } sth![ ] ``` **After this PR** ```rust macro_rules! sth { () => {}; } sth![ ]; ``` --- .../src/handlers/toggle_macro_delimiter.rs | 149 +++++++++++++++++- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs index bf1546986e..60b0797f02 100644 --- a/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs +++ b/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs @@ -86,7 +86,14 @@ pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) } MacroDelims::LCur | MacroDelims::RCur => { editor.replace(ltoken, make.token(T!['['])); - editor.replace(rtoken, make.token(T![']'])); + if semicolon.is_some() || !needs_semicolon(token_tree) { + editor.replace(rtoken, make.token(T![']'])); + } else { + editor.replace_with_many( + rtoken, + vec![make.token(T![']']).into(), make.token(T![;]).into()], + ); + } } } editor.add_mappings(make.finish_with_mappings()); @@ -103,6 +110,30 @@ fn macro_semicolon(makro: &ast::MacroCall) -> Option { }) } +fn needs_semicolon(tt: ast::TokenTree) -> bool { + (|| { + let call = ast::MacroCall::cast(tt.syntax().parent()?)?; + let container = call.syntax().parent()?; + let kind = container.kind(); + + if call.semicolon_token().is_some() { + return Some(false); + } + + Some( + ast::ItemList::can_cast(kind) + || ast::SourceFile::can_cast(kind) + || ast::AssocItemList::can_cast(kind) + || ast::ExternItemList::can_cast(kind) + || ast::MacroItems::can_cast(kind) + || ast::MacroExpr::can_cast(kind) + && ast::ExprStmt::cast(container.parent()?) + .is_some_and(|it| it.semicolon_token().is_none()), + ) + })() + .unwrap_or(false) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -161,7 +192,7 @@ macro_rules! sth { () => {}; } -sth!$0{ }; +sth!$0{ } "#, r#" macro_rules! sth { @@ -170,7 +201,117 @@ macro_rules! sth { sth![ ]; "#, - ) + ); + + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {}; +} + +fn foo() -> i32 { + sth!$0{ } + 2 +} + "#, + r#" +macro_rules! sth { + () => {}; +} + +fn foo() -> i32 { + sth![ ]; + 2 +} + "#, + ); + + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {2}; +} + +fn foo() { + sth!$0{ }; +} + "#, + r#" +macro_rules! sth { + () => {2}; +} + +fn foo() { + sth![ ]; +} + "#, + ); + + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {2}; +} + +fn foo() -> i32 { + sth!$0{ } +} + "#, + r#" +macro_rules! sth { + () => {2}; +} + +fn foo() -> i32 { + sth![ ] +} + "#, + ); + + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {}; +} +impl () { + sth!$0{} +} + "#, + r#" +macro_rules! sth { + () => {}; +} +impl () { + sth![]; +} + "#, + ); + + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {2}; +} + +fn foo() -> i32 { + bar(sth!$0{ }) +} + "#, + r#" +macro_rules! sth { + () => {2}; +} + +fn foo() -> i32 { + bar(sth![ ]) +} + "#, + ); } #[test] @@ -204,7 +345,7 @@ mod abc { () => {}; } - sth!$0{ }; + sth!$0{ } } "#, r#"