aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/replace_let_with_if_let.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers/replace_let_with_if_let.rs')
-rw-r--r--crates/assists/src/handlers/replace_let_with_if_let.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs
new file mode 100644
index 000000000..ed6d0c29b
--- /dev/null
+++ b/crates/assists/src/handlers/replace_let_with_if_let.rs
@@ -0,0 +1,100 @@
1use std::iter::once;
2
3use syntax::{
4 ast::{
5 self,
6 edit::{AstNodeEdit, IndentLevel},
7 make,
8 },
9 AstNode, T,
10};
11
12use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists};
13
14// Assist: replace_let_with_if_let
15//
16// Replaces `let` with an `if-let`.
17//
18// ```
19// # enum Option<T> { Some(T), None }
20//
21// fn main(action: Action) {
22// <|>let x = compute();
23// }
24//
25// fn compute() -> Option<i32> { None }
26// ```
27// ->
28// ```
29// # enum Option<T> { Some(T), None }
30//
31// fn main(action: Action) {
32// if let Some(x) = compute() {
33// }
34// }
35//
36// fn compute() -> Option<i32> { None }
37// ```
38pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 let let_kw = ctx.find_token_at_offset(T![let])?;
40 let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?;
41 let init = let_stmt.initializer()?;
42 let original_pat = let_stmt.pat()?;
43 let ty = ctx.sema.type_of_expr(&init)?;
44 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty).map(|it| it.happy_case());
45
46 let target = let_kw.text_range();
47 acc.add(
48 AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite),
49 "Replace with if-let",
50 target,
51 |edit| {
52 let with_placeholder: ast::Pat = match happy_variant {
53 None => make::wildcard_pat().into(),
54 Some(var_name) => make::tuple_struct_pat(
55 make::path_unqualified(make::path_segment(make::name_ref(var_name))),
56 once(make::wildcard_pat().into()),
57 )
58 .into(),
59 };
60 let block =
61 make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax()));
62 let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block);
63 let stmt = make::expr_stmt(if_);
64
65 let placeholder = stmt.syntax().descendants().find_map(ast::WildcardPat::cast).unwrap();
66 let stmt = stmt.replace_descendant(placeholder.into(), original_pat);
67
68 edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
69 },
70 )
71}
72
73#[cfg(test)]
74mod tests {
75 use crate::tests::check_assist;
76
77 use super::*;
78
79 #[test]
80 fn replace_let_unknown_enum() {
81 check_assist(
82 replace_let_with_if_let,
83 r"
84enum E<T> { X(T), Y(T) }
85
86fn main() {
87 <|>let x = E::X(92);
88}
89 ",
90 r"
91enum E<T> { X(T), Y(T) }
92
93fn main() {
94 if let x = E::X(92) {
95 }
96}
97 ",
98 )
99 }
100}