mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Improve "match to let-else" assist
This commit is contained in:
parent
f1b257f4eb
commit
1f20804b6e
1 changed files with 60 additions and 15 deletions
|
@ -30,7 +30,7 @@ use crate::{
|
||||||
// ```
|
// ```
|
||||||
pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||||
let let_stmt: ast::LetStmt = ctx.find_node_at_offset()?;
|
let let_stmt: ast::LetStmt = ctx.find_node_at_offset()?;
|
||||||
let binding = find_binding(let_stmt.pat()?)?;
|
let binding = let_stmt.pat()?;
|
||||||
|
|
||||||
let initializer = match let_stmt.initializer() {
|
let initializer = match let_stmt.initializer() {
|
||||||
Some(ast::Expr::MatchExpr(it)) => it,
|
Some(ast::Expr::MatchExpr(it)) => it,
|
||||||
|
@ -47,7 +47,12 @@ pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let diverging_arm_expr = diverging_arm.expr()?;
|
let diverging_arm_expr = match diverging_arm.expr()? {
|
||||||
|
ast::Expr::BlockExpr(block) if block.modifier().is_none() && block.label().is_none() => {
|
||||||
|
block.to_string()
|
||||||
|
}
|
||||||
|
other => format!("{{ {other} }}"),
|
||||||
|
};
|
||||||
let extracting_arm_pat = extracting_arm.pat()?;
|
let extracting_arm_pat = extracting_arm.pat()?;
|
||||||
let extracted_variable = find_extracted_variable(ctx, &extracting_arm)?;
|
let extracted_variable = find_extracted_variable(ctx, &extracting_arm)?;
|
||||||
|
|
||||||
|
@ -56,24 +61,16 @@ pub(crate) fn convert_match_to_let_else(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
"Convert match to let-else",
|
"Convert match to let-else",
|
||||||
let_stmt.syntax().text_range(),
|
let_stmt.syntax().text_range(),
|
||||||
|builder| {
|
|builder| {
|
||||||
let extracting_arm_pat = rename_variable(&extracting_arm_pat, extracted_variable, binding);
|
let extracting_arm_pat =
|
||||||
|
rename_variable(&extracting_arm_pat, extracted_variable, binding);
|
||||||
builder.replace(
|
builder.replace(
|
||||||
let_stmt.syntax().text_range(),
|
let_stmt.syntax().text_range(),
|
||||||
format!("let {extracting_arm_pat} = {initializer_expr} else {{ {diverging_arm_expr} }};")
|
format!("let {extracting_arm_pat} = {initializer_expr} else {diverging_arm_expr};"),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a pattern, find the name introduced to the surrounding scope.
|
|
||||||
fn find_binding(pat: ast::Pat) -> Option<ast::IdentPat> {
|
|
||||||
if let ast::Pat::IdentPat(ident) = pat {
|
|
||||||
Some(ident)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a match expression, find extracting and diverging arms.
|
// Given a match expression, find extracting and diverging arms.
|
||||||
fn find_arms(
|
fn find_arms(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
|
@ -124,7 +121,7 @@ fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Opti
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename `extracted` with `binding` in `pat`.
|
// Rename `extracted` with `binding` in `pat`.
|
||||||
fn rename_variable(pat: &ast::Pat, extracted: ast::Name, binding: ast::IdentPat) -> SyntaxNode {
|
fn rename_variable(pat: &ast::Pat, extracted: ast::Name, binding: ast::Pat) -> SyntaxNode {
|
||||||
let syntax = pat.syntax().clone_for_update();
|
let syntax = pat.syntax().clone_for_update();
|
||||||
let extracted_syntax = syntax.covering_element(extracted.syntax().text_range());
|
let extracted_syntax = syntax.covering_element(extracted.syntax().text_range());
|
||||||
|
|
||||||
|
@ -136,7 +133,7 @@ fn rename_variable(pat: &ast::Pat, extracted: ast::Name, binding: ast::IdentPat)
|
||||||
if let Some(name_ref) = record_pat_field.field_name() {
|
if let Some(name_ref) = record_pat_field.field_name() {
|
||||||
ted::replace(
|
ted::replace(
|
||||||
record_pat_field.syntax(),
|
record_pat_field.syntax(),
|
||||||
ast::make::record_pat_field(ast::make::name_ref(&name_ref.text()), binding.into())
|
ast::make::record_pat_field(ast::make::name_ref(&name_ref.text()), binding)
|
||||||
.syntax()
|
.syntax()
|
||||||
.clone_for_update(),
|
.clone_for_update(),
|
||||||
);
|
);
|
||||||
|
@ -410,4 +407,52 @@ fn foo(opt: Option<i32>) -> Option<i32> {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complex_pattern() {
|
||||||
|
check_assist(
|
||||||
|
convert_match_to_let_else,
|
||||||
|
r#"
|
||||||
|
//- minicore: option
|
||||||
|
fn f() {
|
||||||
|
let (x, y) = $0match Some((0, 1)) {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn f() {
|
||||||
|
let Some((x, y)) = Some((0, 1)) else { return };
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diverging_block() {
|
||||||
|
check_assist(
|
||||||
|
convert_match_to_let_else,
|
||||||
|
r#"
|
||||||
|
//- minicore: option
|
||||||
|
fn f() {
|
||||||
|
let x = $0match Some(()) {
|
||||||
|
Some(it) => it,
|
||||||
|
None => {//comment
|
||||||
|
println!("nope");
|
||||||
|
return
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn f() {
|
||||||
|
let Some(x) = Some(()) else {//comment
|
||||||
|
println!("nope");
|
||||||
|
return
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue