Skip to content

Commit 12d33ea

Browse files
bors[bot]Crauzer
andauthored
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 <[email protected]>
2 parents eb60836 + 1161fa4 commit 12d33ea

File tree

5 files changed

+185
-3
lines changed

5 files changed

+185
-3
lines changed

crates/ide_assists/src/handlers/replace_if_let_with_match.rs

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

crates/ide_assists/src/lib.rs

+2
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_assists/src/tests/generated.rs

+21
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,27 @@ fn main() {
17201720
)
17211721
}
17221722

1723+
#[test]
1724+
fn doctest_replace_try_expr_with_match() {
1725+
check_doc_test(
1726+
"replace_try_expr_with_match",
1727+
r#####"
1728+
//- minicore:option
1729+
fn handle() {
1730+
let pat = Some(true)$0?;
1731+
}
1732+
"#####,
1733+
r#####"
1734+
fn handle() {
1735+
let pat = match Some(true) {
1736+
Some(it) => it,
1737+
None => return None,
1738+
};
1739+
}
1740+
"#####,
1741+
)
1742+
}
1743+
17231744
#[test]
17241745
fn doctest_sort_items() {
17251746
check_doc_test(

crates/ide_db/src/ty_filter.rs

+13-2
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)