Skip to content

Commit 05e58af

Browse files
committed
Add replace_try_expr_with_match assist
1 parent 4cfe237 commit 05e58af

File tree

4 files changed

+159
-3
lines changed

4 files changed

+159
-3
lines changed

crates/ide_assists/src/handlers/replace_if_let_with_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ fn make_else_arm(
142142
let pattern = match pattern {
143143
Some((it, pat)) => {
144144
if does_pat_match_variant(pat, &it.sad_pattern()) {
145-
it.happy_pattern()
145+
it.happy_pattern_wildcard()
146146
} else {
147147
it.sad_pattern()
148148
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
use std::iter;
2+
3+
use ide_db::{
4+
assists::{AssistId, AssistKind},
5+
ty_filter::TryEnum,
6+
};
7+
use syntax::{
8+
ast::{
9+
self,
10+
edit::{AstNodeEdit, IndentLevel},
11+
make,
12+
},
13+
AstNode, T,
14+
};
15+
16+
use crate::assist_context::{AssistContext, Assists};
17+
18+
// Assist: replace_try_expr_with_match
19+
//
20+
// Replaces a `try` expression with a `match` expression.
21+
//
22+
// ```
23+
// let pat = Some(true)$0?;
24+
// ```
25+
// ->
26+
// ```
27+
//let pat = match Some(true) {
28+
// Some(it) => it,
29+
// None => return None,
30+
//};
31+
// ```
32+
pub(crate) fn replace_try_expr_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33+
let qm_kw = ctx.find_token_syntax_at_offset(T![?])?;
34+
let qm_kw_parent = qm_kw.parent().and_then(ast::TryExpr::cast)?;
35+
36+
let expr = qm_kw_parent.expr()?;
37+
let expr_type_info = ctx.sema.type_of_expr(&expr)?;
38+
39+
let try_enum = TryEnum::from_ty(&ctx.sema, &expr_type_info.original)?;
40+
41+
let target = qm_kw_parent.syntax().text_range();
42+
acc.add(
43+
AssistId("replace_try_expr_with_match", AssistKind::RefactorRewrite),
44+
"Replace try expression with match",
45+
target,
46+
|edit| {
47+
let sad_pat = match try_enum {
48+
TryEnum::Option => make::path_pat(make::ext::ident_path("None")),
49+
TryEnum::Result => make::tuple_struct_pat(
50+
make::ext::ident_path("Err"),
51+
iter::once(make::path_pat(make::ext::ident_path("err"))),
52+
)
53+
.into(),
54+
};
55+
let sad_expr = match try_enum {
56+
TryEnum::Option => {
57+
make::expr_return(Some(make::expr_path(make::ext::ident_path("None"))))
58+
}
59+
TryEnum::Result => make::expr_return(Some(make::expr_call(
60+
make::expr_path(make::ext::ident_path("Err")),
61+
make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))),
62+
))),
63+
};
64+
65+
let happy_arm = make::match_arm(
66+
iter::once(
67+
try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
68+
),
69+
None,
70+
make::expr_path(make::ext::ident_path("it")),
71+
);
72+
let sad_arm = make::match_arm(iter::once(sad_pat), None, sad_expr);
73+
74+
let match_arms = [happy_arm, sad_arm];
75+
let match_arm_list = make::match_arm_list(std::array::IntoIter::new(match_arms));
76+
77+
let expr_match = make::expr_match(expr, match_arm_list)
78+
.indent(IndentLevel::from_node(qm_kw_parent.syntax()));
79+
edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match);
80+
},
81+
)
82+
}
83+
84+
#[cfg(test)]
85+
mod tests {
86+
use super::*;
87+
88+
use crate::tests::{check_assist, check_assist_not_applicable};
89+
90+
#[test]
91+
fn test_replace_try_expr_with_match_not_applicable() {
92+
check_assist_not_applicable(
93+
replace_try_expr_with_match,
94+
r#"
95+
fn test() {
96+
let pat = 25$0;
97+
}
98+
"#,
99+
);
100+
}
101+
102+
#[test]
103+
fn test_replace_try_expr_with_match_option() {
104+
check_assist(
105+
replace_try_expr_with_match,
106+
r#"
107+
//- minicore:option
108+
fn test() {
109+
let pat = Some(true)$0?;
110+
}
111+
"#,
112+
r#"
113+
fn test() {
114+
let pat = match Some(true) {
115+
Some(it) => it,
116+
None => return None,
117+
};
118+
}
119+
"#,
120+
);
121+
}
122+
123+
#[test]
124+
fn test_replace_try_expr_with_match_result() {
125+
check_assist(
126+
replace_try_expr_with_match,
127+
r#"
128+
//- minicore:result
129+
fn test() {
130+
let pat = Ok(true)$0?;
131+
}
132+
"#,
133+
r#"
134+
fn test() {
135+
let pat = match Ok(true) {
136+
Ok(it) => it,
137+
Err(err) => return Err(err),
138+
};
139+
}
140+
"#,
141+
);
142+
}
143+
}

crates/ide_assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ mod handlers {
164164
mod remove_unused_param;
165165
mod reorder_fields;
166166
mod reorder_impl;
167+
mod replace_try_expr_with_match;
167168
mod replace_derive_with_manual_impl;
168169
mod replace_if_let_with_match;
169170
mod introduce_named_generic;
@@ -243,6 +244,7 @@ mod handlers {
243244
remove_unused_param::remove_unused_param,
244245
reorder_fields::reorder_fields,
245246
reorder_impl::reorder_impl,
247+
replace_try_expr_with_match::replace_try_expr_with_match,
246248
replace_derive_with_manual_impl::replace_derive_with_manual_impl,
247249
replace_if_let_with_match::replace_if_let_with_match,
248250
replace_if_let_with_match::replace_match_with_if_let,

crates/ide_db/src/ty_filter.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::iter;
66

77
use hir::Semantics;
8-
use syntax::ast::{self, make};
8+
use syntax::ast::{self, make, Pat};
99

1010
use crate::RootDatabase;
1111

@@ -51,7 +51,18 @@ impl TryEnum {
5151
}
5252
}
5353

54-
pub fn happy_pattern(self) -> ast::Pat {
54+
pub fn happy_pattern(self, pat: Pat) -> ast::Pat {
55+
match self {
56+
TryEnum::Result => {
57+
make::tuple_struct_pat(make::ext::ident_path("Ok"), iter::once(pat)).into()
58+
}
59+
TryEnum::Option => {
60+
make::tuple_struct_pat(make::ext::ident_path("Some"), iter::once(pat)).into()
61+
}
62+
}
63+
}
64+
65+
pub fn happy_pattern_wildcard(self) -> ast::Pat {
5566
match self {
5667
TryEnum::Result => make::tuple_struct_pat(
5768
make::ext::ident_path("Ok"),

0 commit comments

Comments
 (0)