Unnamed repository; edit this file 'description' to name the repository.
Add replace_try_expr_with_match assist
crauzer 2021-10-07
parent 4cfe237 · commit 05e58af
-rw-r--r--crates/ide_assists/src/handlers/replace_if_let_with_match.rs2
-rw-r--r--crates/ide_assists/src/handlers/replace_try_expr_with_match.rs143
-rw-r--r--crates/ide_assists/src/lib.rs2
-rw-r--r--crates/ide_db/src/ty_filter.rs15
4 files changed, 159 insertions, 3 deletions
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
index 22675fbee0..8aad3e2f52 100644
--- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
@@ -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()
}
diff --git a/crates/ide_assists/src/handlers/replace_try_expr_with_match.rs b/crates/ide_assists/src/handlers/replace_try_expr_with_match.rs
new file mode 100644
index 0000000000..6fb784b7f4
--- /dev/null
+++ b/crates/ide_assists/src/handlers/replace_try_expr_with_match.rs
@@ -0,0 +1,143 @@
+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.
+//
+// ```
+// let pat = Some(true)$0?;
+// ```
+// ->
+// ```
+//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 = 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),
+ };
+}
+ "#,
+ );
+ }
+}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index bec51c508b..a0629afb1d 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -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 @@ mod handlers {
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,
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs
index 370d0df007..28c01d3173 100644
--- a/crates/ide_db/src/ty_filter.rs
+++ b/crates/ide_db/src/ty_filter.rs
@@ -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 @@ impl TryEnum {
}
}
- 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"),