Merge #10476
10476: feat: Add `replace_try_expr_with_match` assist r=Veykril a=Crauzer Adds the replace_try_expr_with_match assist #10424 Co-authored-by: crauzer <filip.quitko@gmail.com>
This commit is contained in:
commit
12d33eafaf
@ -142,7 +142,7 @@ fn make_else_arm(
|
||||
let pattern = match pattern {
|
||||
Some((it, pat)) => {
|
||||
if does_pat_match_variant(pat, &it.sad_pattern()) {
|
||||
it.happy_pattern()
|
||||
it.happy_pattern_wildcard()
|
||||
} else {
|
||||
it.sad_pattern()
|
||||
}
|
||||
|
148
crates/ide_assists/src/handlers/replace_try_expr_with_match.rs
Normal file
148
crates/ide_assists/src/handlers/replace_try_expr_with_match.rs
Normal file
@ -0,0 +1,148 @@
|
||||
use std::iter;
|
||||
|
||||
use ide_db::{
|
||||
assists::{AssistId, AssistKind},
|
||||
ty_filter::TryEnum,
|
||||
};
|
||||
use syntax::{
|
||||
ast::{
|
||||
self,
|
||||
edit::{AstNodeEdit, IndentLevel},
|
||||
make,
|
||||
},
|
||||
AstNode, T,
|
||||
};
|
||||
|
||||
use crate::assist_context::{AssistContext, Assists};
|
||||
|
||||
// Assist: replace_try_expr_with_match
|
||||
//
|
||||
// Replaces a `try` expression with a `match` expression.
|
||||
//
|
||||
// ```
|
||||
// # //- minicore:option
|
||||
// fn handle() {
|
||||
// let pat = Some(true)$0?;
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// fn handle() {
|
||||
// let pat = match Some(true) {
|
||||
// Some(it) => it,
|
||||
// None => return None,
|
||||
// };
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn replace_try_expr_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let qm_kw = ctx.find_token_syntax_at_offset(T![?])?;
|
||||
let qm_kw_parent = qm_kw.parent().and_then(ast::TryExpr::cast)?;
|
||||
|
||||
let expr = qm_kw_parent.expr()?;
|
||||
let expr_type_info = ctx.sema.type_of_expr(&expr)?;
|
||||
|
||||
let try_enum = TryEnum::from_ty(&ctx.sema, &expr_type_info.original)?;
|
||||
|
||||
let target = qm_kw_parent.syntax().text_range();
|
||||
acc.add(
|
||||
AssistId("replace_try_expr_with_match", AssistKind::RefactorRewrite),
|
||||
"Replace try expression with match",
|
||||
target,
|
||||
|edit| {
|
||||
let sad_pat = match try_enum {
|
||||
TryEnum::Option => make::path_pat(make::ext::ident_path("None")),
|
||||
TryEnum::Result => make::tuple_struct_pat(
|
||||
make::ext::ident_path("Err"),
|
||||
iter::once(make::path_pat(make::ext::ident_path("err"))),
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
let sad_expr = match try_enum {
|
||||
TryEnum::Option => {
|
||||
make::expr_return(Some(make::expr_path(make::ext::ident_path("None"))))
|
||||
}
|
||||
TryEnum::Result => make::expr_return(Some(make::expr_call(
|
||||
make::expr_path(make::ext::ident_path("Err")),
|
||||
make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))),
|
||||
))),
|
||||
};
|
||||
|
||||
let happy_arm = make::match_arm(
|
||||
iter::once(
|
||||
try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
|
||||
),
|
||||
None,
|
||||
make::expr_path(make::ext::ident_path("it")),
|
||||
);
|
||||
let sad_arm = make::match_arm(iter::once(sad_pat), None, sad_expr);
|
||||
|
||||
let match_arms = [happy_arm, sad_arm];
|
||||
let match_arm_list = make::match_arm_list(std::array::IntoIter::new(match_arms));
|
||||
|
||||
let expr_match = make::expr_match(expr, match_arm_list)
|
||||
.indent(IndentLevel::from_node(qm_kw_parent.syntax()));
|
||||
edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
|
||||
#[test]
|
||||
fn test_replace_try_expr_with_match_not_applicable() {
|
||||
check_assist_not_applicable(
|
||||
replace_try_expr_with_match,
|
||||
r#"
|
||||
fn test() {
|
||||
let pat: u32 = 25$0;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_try_expr_with_match_option() {
|
||||
check_assist(
|
||||
replace_try_expr_with_match,
|
||||
r#"
|
||||
//- minicore:option
|
||||
fn test() {
|
||||
let pat = Some(true)$0?;
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn test() {
|
||||
let pat = match Some(true) {
|
||||
Some(it) => it,
|
||||
None => return None,
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_try_expr_with_match_result() {
|
||||
check_assist(
|
||||
replace_try_expr_with_match,
|
||||
r#"
|
||||
//- minicore:result
|
||||
fn test() {
|
||||
let pat = Ok(true)$0?;
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn test() {
|
||||
let pat = match Ok(true) {
|
||||
Ok(it) => it,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
@ -164,6 +164,7 @@ mod handlers {
|
||||
mod remove_unused_param;
|
||||
mod reorder_fields;
|
||||
mod reorder_impl;
|
||||
mod replace_try_expr_with_match;
|
||||
mod replace_derive_with_manual_impl;
|
||||
mod replace_if_let_with_match;
|
||||
mod introduce_named_generic;
|
||||
@ -243,6 +244,7 @@ pub(crate) fn all() -> &'static [Handler] {
|
||||
remove_unused_param::remove_unused_param,
|
||||
reorder_fields::reorder_fields,
|
||||
reorder_impl::reorder_impl,
|
||||
replace_try_expr_with_match::replace_try_expr_with_match,
|
||||
replace_derive_with_manual_impl::replace_derive_with_manual_impl,
|
||||
replace_if_let_with_match::replace_if_let_with_match,
|
||||
replace_if_let_with_match::replace_match_with_if_let,
|
||||
|
@ -1720,6 +1720,27 @@ fn main() {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_replace_try_expr_with_match() {
|
||||
check_doc_test(
|
||||
"replace_try_expr_with_match",
|
||||
r#####"
|
||||
//- minicore:option
|
||||
fn handle() {
|
||||
let pat = Some(true)$0?;
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
fn handle() {
|
||||
let pat = match Some(true) {
|
||||
Some(it) => it,
|
||||
None => return None,
|
||||
};
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_sort_items() {
|
||||
check_doc_test(
|
||||
|
@ -5,7 +5,7 @@
|
||||
use std::iter;
|
||||
|
||||
use hir::Semantics;
|
||||
use syntax::ast::{self, make};
|
||||
use syntax::ast::{self, make, Pat};
|
||||
|
||||
use crate::RootDatabase;
|
||||
|
||||
@ -51,7 +51,18 @@ pub fn sad_pattern(self) -> ast::Pat {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn happy_pattern(self) -> ast::Pat {
|
||||
pub fn happy_pattern(self, pat: Pat) -> ast::Pat {
|
||||
match self {
|
||||
TryEnum::Result => {
|
||||
make::tuple_struct_pat(make::ext::ident_path("Ok"), iter::once(pat)).into()
|
||||
}
|
||||
TryEnum::Option => {
|
||||
make::tuple_struct_pat(make::ext::ident_path("Some"), iter::once(pat)).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn happy_pattern_wildcard(self) -> ast::Pat {
|
||||
match self {
|
||||
TryEnum::Result => make::tuple_struct_pat(
|
||||
make::ext::ident_path("Ok"),
|
||||
|
Loading…
Reference in New Issue
Block a user