diff --git a/crates/assists/src/handlers/move_guard.rs b/crates/assists/src/handlers/move_guard.rs index 452115fe6721..e1855b63d41a 100644 --- a/crates/assists/src/handlers/move_guard.rs +++ b/crates/assists/src/handlers/move_guard.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{edit::AstNodeEdit, make, AstNode, IfExpr, MatchArm}, + ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, Expr, IfExpr, MatchArm}, SyntaxKind::WHITESPACE, }; @@ -92,9 +92,20 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let match_arm: MatchArm = ctx.find_node_at_offset::()?; let match_pat = match_arm.pat()?; - let arm_body = match_arm.expr()?; - let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?; + + let mut replace_node = None; + let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| { + let block_expr = BlockExpr::cast(arm_body.syntax().clone())?; + if let Expr::IfExpr(e) = block_expr.expr()? { + replace_node = Some(block_expr.syntax().clone()); + Some(e) + } else { + None + } + })?; + let replace_node = replace_node.unwrap_or_else(|| if_expr.syntax().clone()); + let cond = if_expr.condition()?; let then_block = if_expr.then_branch()?; @@ -109,19 +120,23 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex let buf = format!(" if {}", cond.syntax().text()); - let target = if_expr.syntax().text_range(); acc.add( AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite), "Move condition to match guard", - target, + replace_node.text_range(), |edit| { let then_only_expr = then_block.statements().next().is_none(); match &then_block.expr() { Some(then_expr) if then_only_expr => { - edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) + edit.replace(replace_node.text_range(), then_expr.syntax().text()) } - _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()), + _ if replace_node != *if_expr.syntax() => { + // Dedent because if_expr is in a BlockExpr + let replace_with = then_block.dedent(1.into()).syntax().text(); + edit.replace(replace_node.text_range(), replace_with) + } + _ => edit.replace(replace_node.text_range(), then_block.syntax().text()), } edit.insert(match_pat.syntax().text_range().end(), buf); @@ -224,6 +239,33 @@ fn main() { ); } + #[test] + fn move_arm_cond_in_block_to_match_guard_works() { + check_assist( + move_arm_cond_to_match_guard, + r#" +fn main() { + match 92 { + x => { + <|>if x > 10 { + false + } + }, + _ => true + } +} +"#, + r#" +fn main() { + match 92 { + x if x > 10 => false, + _ => true + } +} +"#, + ); + } + #[test] fn move_arm_cond_to_match_guard_if_let_not_works() { check_assist_not_applicable( @@ -290,4 +332,35 @@ fn main() { "#, ); } + + #[test] + fn move_arm_cond_in_block_to_match_guard_if_multiline_body_works() { + check_assist( + move_arm_cond_to_match_guard, + r#" +fn main() { + match 92 { + x => { + if x > 10 { + 92;<|> + false + } + } + _ => true + } +} +"#, + r#" +fn main() { + match 92 { + x if x > 10 => { + 92; + false + } + _ => true + } +} +"#, + ) + } } diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 562e92252b2a..4ab206a838e5 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -184,7 +184,11 @@ fn opt_visibility(p: &mut Parser) -> bool { // pub(self) struct S; // pub(self) struct S; // pub(self) struct S; - T![crate] | T![self] | T![super] => { + + // test pub_parens_typepath + // struct B(pub (super::A)); + // struct B(pub (crate::A,)); + T![crate] | T![self] | T![super] if p.nth(2) != T![:] => { p.bump_any(); p.bump_any(); p.expect(T![')']); diff --git a/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast b/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast new file mode 100644 index 000000000000..c204f0e2d944 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast @@ -0,0 +1,54 @@ +SOURCE_FILE@0..53 + STRUCT@0..25 + STRUCT_KW@0..6 "struct" + WHITESPACE@6..7 " " + NAME@7..8 + IDENT@7..8 "B" + TUPLE_FIELD_LIST@8..24 + L_PAREN@8..9 "(" + TUPLE_FIELD@9..23 + VISIBILITY@9..12 + PUB_KW@9..12 "pub" + WHITESPACE@12..13 " " + PAREN_TYPE@13..23 + L_PAREN@13..14 "(" + PATH_TYPE@14..22 + PATH@14..22 + PATH@14..19 + PATH_SEGMENT@14..19 + SUPER_KW@14..19 "super" + COLON2@19..21 "::" + PATH_SEGMENT@21..22 + NAME_REF@21..22 + IDENT@21..22 "A" + R_PAREN@22..23 ")" + R_PAREN@23..24 ")" + SEMICOLON@24..25 ";" + WHITESPACE@25..26 "\n" + STRUCT@26..52 + STRUCT_KW@26..32 "struct" + WHITESPACE@32..33 " " + NAME@33..34 + IDENT@33..34 "B" + TUPLE_FIELD_LIST@34..51 + L_PAREN@34..35 "(" + TUPLE_FIELD@35..50 + VISIBILITY@35..38 + PUB_KW@35..38 "pub" + WHITESPACE@38..39 " " + TUPLE_TYPE@39..50 + L_PAREN@39..40 "(" + PATH_TYPE@40..48 + PATH@40..48 + PATH@40..45 + PATH_SEGMENT@40..45 + CRATE_KW@40..45 "crate" + COLON2@45..47 "::" + PATH_SEGMENT@47..48 + NAME_REF@47..48 + IDENT@47..48 "A" + COMMA@48..49 "," + R_PAREN@49..50 ")" + R_PAREN@50..51 ")" + SEMICOLON@51..52 ";" + WHITESPACE@52..53 "\n" diff --git a/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rs b/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rs new file mode 100644 index 000000000000..d4c1638226ea --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rs @@ -0,0 +1,2 @@ +struct B(pub (super::A)); +struct B(pub (crate::A,));