Skip to content

Commit 9006fee

Browse files
Merge pull request #22179 from A4-Tacks/pure-unwrap-block
feat: Add unwrap_block, offer unwrap_block and unwrap_branch
2 parents 5d9bcee + fcd9a26 commit 9006fee

3 files changed

Lines changed: 188 additions & 1 deletion

File tree

crates/ide-assists/src/handlers/unwrap_branch.rs

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use either::Either;
12
use syntax::{
23
AstNode, SyntaxElement, SyntaxKind, SyntaxNode, T,
34
ast::{
@@ -86,6 +87,55 @@ pub(crate) fn unwrap_branch(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
8687
})
8788
}
8889

90+
// Assist: unwrap_block
91+
//
92+
// This assist removes braces and unwrap single expressions block.
93+
//
94+
// ```
95+
// fn foo() {
96+
// match () {
97+
// _ => {$0
98+
// bar()
99+
// }
100+
// }
101+
// }
102+
// ```
103+
// ->
104+
// ```
105+
// fn foo() {
106+
// match () {
107+
// _ => bar(),
108+
// }
109+
// }
110+
// ```
111+
pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
112+
let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?;
113+
let block = l_curly_token.parent_ancestors().nth(1).and_then(ast::BlockExpr::cast)?;
114+
let target = block.syntax().text_range();
115+
let tail_expr = block.tail_expr()?;
116+
let stmt_list = block.stmt_list()?;
117+
let container = Either::<ast::MatchArm, ast::ClosureExpr>::cast(block.syntax().parent()?)?;
118+
119+
if stmt_list.statements().next().is_some() {
120+
return None;
121+
}
122+
123+
acc.add(AssistId::refactor_rewrite("unwrap_block"), "Unwrap block", target, |builder| {
124+
let editor = builder.make_editor(block.syntax());
125+
let replacement = stmt_list.dedent(tail_expr.indent_level()).indent(block.indent_level());
126+
let mut replacement = extract_statements(replacement);
127+
128+
if container.left().is_some_and(|it| it.comma_token().is_none())
129+
&& !tail_expr.is_block_like()
130+
{
131+
replacement.push(editor.make().token(T![,]).into());
132+
}
133+
134+
editor.replace_with_many(block.syntax(), replacement);
135+
builder.add_file_edits(ctx.vfs_file_id(), editor);
136+
})
137+
}
138+
89139
fn delete_else_before(container: SyntaxNode, editor: &SyntaxEditor) {
90140
let make = editor.make();
91141
let Some(else_token) = container
@@ -158,7 +208,10 @@ fn wrap_block_raw(expr: &ast::Expr, make: &SyntaxFactory) -> ast::BlockExpr {
158208

159209
#[cfg(test)]
160210
mod tests {
161-
use crate::tests::{check_assist, check_assist_not_applicable, check_assist_with_label};
211+
use crate::tests::{
212+
check_assist, check_assist_by_label, check_assist_not_applicable,
213+
check_assist_not_applicable_by_label, check_assist_with_label,
214+
};
162215

163216
use super::*;
164217

@@ -1037,4 +1090,114 @@ fn main() {
10371090
"Unwrap branch",
10381091
);
10391092
}
1093+
1094+
#[test]
1095+
fn unwrap_block_in_branch() {
1096+
check_assist_by_label(
1097+
unwrap_block,
1098+
r#"
1099+
fn main() {
1100+
match rel_path {
1101+
Ok(rel_path) => {$0
1102+
if true {
1103+
foo()
1104+
}
1105+
}
1106+
Err(_) => None,
1107+
}
1108+
}
1109+
"#,
1110+
r#"
1111+
fn main() {
1112+
match rel_path {
1113+
Ok(rel_path) => if true {
1114+
foo()
1115+
}
1116+
Err(_) => None,
1117+
}
1118+
}
1119+
"#,
1120+
"Unwrap block",
1121+
);
1122+
1123+
check_assist_by_label(
1124+
unwrap_block,
1125+
r#"
1126+
fn main() {
1127+
match rel_path {
1128+
Ok(rel_path) => {$0
1129+
1 + 2
1130+
}
1131+
Err(_) => None,
1132+
}
1133+
}
1134+
"#,
1135+
r#"
1136+
fn main() {
1137+
match rel_path {
1138+
Ok(rel_path) => 1 + 2,
1139+
Err(_) => None,
1140+
}
1141+
}
1142+
"#,
1143+
"Unwrap block",
1144+
);
1145+
}
1146+
1147+
#[test]
1148+
fn unwrap_block_in_branch_non_standalone() {
1149+
check_assist_not_applicable_by_label(
1150+
unwrap_block,
1151+
r#"
1152+
fn main() {
1153+
match rel_path {
1154+
Ok(rel_path) => {
1155+
if true {$0
1156+
foo()
1157+
}
1158+
}
1159+
Err(_) => None,
1160+
}
1161+
}
1162+
"#,
1163+
"Unwrap block",
1164+
);
1165+
}
1166+
1167+
#[test]
1168+
fn unwrap_block_in_branch_non_tail_expr_only() {
1169+
check_assist_not_applicable_by_label(
1170+
unwrap_block,
1171+
r#"
1172+
fn main() {
1173+
match rel_path {
1174+
Ok(rel_path) => {$0
1175+
x;
1176+
y
1177+
}
1178+
Err(_) => None,
1179+
}
1180+
}
1181+
"#,
1182+
"Unwrap block",
1183+
);
1184+
}
1185+
1186+
#[test]
1187+
fn unwrap_block_in_closure() {
1188+
check_assist_by_label(
1189+
unwrap_block,
1190+
r#"
1191+
fn main() {
1192+
let f = || {$0 foo() };
1193+
}
1194+
"#,
1195+
r#"
1196+
fn main() {
1197+
let f = || foo();
1198+
}
1199+
"#,
1200+
"Unwrap block",
1201+
);
1202+
}
10401203
}

crates/ide-assists/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ mod handlers {
380380
unmerge_imports::unmerge_imports,
381381
unnecessary_async::unnecessary_async,
382382
unqualify_method_call::unqualify_method_call,
383+
unwrap_branch::unwrap_block,
383384
unwrap_branch::unwrap_branch,
384385
unwrap_return_type::unwrap_return_type,
385386
unwrap_tuple::unwrap_tuple,

crates/ide-assists/src/tests/generated.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3730,6 +3730,29 @@ mod std { pub mod ops { pub trait Add { fn add(self, _: Self) {} } impl Add for
37303730
)
37313731
}
37323732

3733+
#[test]
3734+
fn doctest_unwrap_block() {
3735+
check_doc_test(
3736+
"unwrap_block",
3737+
r#####"
3738+
fn foo() {
3739+
match () {
3740+
_ => {$0
3741+
bar()
3742+
}
3743+
}
3744+
}
3745+
"#####,
3746+
r#####"
3747+
fn foo() {
3748+
match () {
3749+
_ => bar(),
3750+
}
3751+
}
3752+
"#####,
3753+
)
3754+
}
3755+
37333756
#[test]
37343757
fn doctest_unwrap_branch() {
37353758
check_doc_test(

0 commit comments

Comments
 (0)