Skip to content

Commit e0446a0

Browse files
committed
implement assist for let stmt with TryEnum type to guarded return
1 parent d410d4a commit e0446a0

File tree

1 file changed

+124
-2
lines changed

1 file changed

+124
-2
lines changed

crates/ide-assists/src/handlers/convert_to_guarded_return.rs

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use std::iter::once;
22

3-
use ide_db::syntax_helpers::node_ext::{is_pattern_cond, single_let};
3+
use ide_db::{
4+
syntax_helpers::node_ext::{is_pattern_cond, single_let},
5+
ty_filter::TryEnum,
6+
};
47
use syntax::{
58
ast::{
69
self,
@@ -41,7 +44,20 @@ use crate::{
4144
// }
4245
// ```
4346
pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
44-
let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
47+
if let Some(let_stmt) = ctx.find_node_at_offset() {
48+
let_stmt_to_guarded_return(let_stmt, acc, ctx)
49+
} else if let Some(if_expr) = ctx.find_node_at_offset() {
50+
if_expr_to_guarded_return(if_expr, acc, ctx)
51+
} else {
52+
None
53+
}
54+
}
55+
56+
fn if_expr_to_guarded_return(
57+
if_expr: ast::IfExpr,
58+
acc: &mut Assists,
59+
_ctx: &AssistContext<'_>,
60+
) -> Option<()> {
4561
if if_expr.else_branch().is_some() {
4662
return None;
4763
}
@@ -148,6 +164,56 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'
148164
)
149165
}
150166

167+
fn let_stmt_to_guarded_return(
168+
let_stmt: ast::LetStmt,
169+
acc: &mut Assists,
170+
ctx: &AssistContext<'_>,
171+
) -> Option<()> {
172+
let pat = let_stmt.pat()?;
173+
let expr = let_stmt.initializer()?;
174+
175+
let try_enum =
176+
ctx.sema.type_of_expr(&expr).and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))?;
177+
178+
let happy_pattern = try_enum.happy_pattern(pat);
179+
let target = let_stmt.syntax().text_range();
180+
181+
let early_expression: ast::Expr = {
182+
let parent_block =
183+
let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
184+
let parent_container = parent_block.syntax().parent()?;
185+
186+
match parent_container.kind() {
187+
WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
188+
FN => make::expr_return(None),
189+
_ => return None,
190+
}
191+
};
192+
193+
acc.add(
194+
AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
195+
"Convert to guarded return",
196+
target,
197+
|edit| {
198+
let let_stmt = edit.make_mut(let_stmt);
199+
let let_indent_level = IndentLevel::from_node(let_stmt.syntax());
200+
201+
let replacement = {
202+
let let_else_stmt = make::let_else_stmt(
203+
happy_pattern,
204+
let_stmt.ty(),
205+
expr,
206+
ast::make::tail_only_block_expr(early_expression),
207+
);
208+
let let_else_stmt = let_else_stmt.indent(let_indent_level);
209+
let_else_stmt.syntax().clone_for_update()
210+
};
211+
212+
ted::replace(let_stmt.syntax(), replacement)
213+
},
214+
)
215+
}
216+
151217
#[cfg(test)]
152218
mod tests {
153219
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -450,6 +516,62 @@ fn main() {
450516
);
451517
}
452518

519+
#[test]
520+
fn convert_let_stmt_inside_fn() {
521+
check_assist(
522+
convert_to_guarded_return,
523+
r#"
524+
//- minicore: option
525+
fn foo() -> Option<i32> {
526+
None
527+
}
528+
529+
fn main() {
530+
let x$0 = foo();
531+
}
532+
"#,
533+
r#"
534+
fn foo() -> Option<i32> {
535+
None
536+
}
537+
538+
fn main() {
539+
let Some(x) = foo() else { return };
540+
}
541+
"#,
542+
);
543+
}
544+
545+
#[test]
546+
fn convert_let_stmt_inside_loop() {
547+
check_assist(
548+
convert_to_guarded_return,
549+
r#"
550+
//- minicore: option
551+
fn foo() -> Option<i32> {
552+
None
553+
}
554+
555+
fn main() {
556+
loop {
557+
let x$0 = foo();
558+
}
559+
}
560+
"#,
561+
r#"
562+
fn foo() -> Option<i32> {
563+
None
564+
}
565+
566+
fn main() {
567+
loop {
568+
let Some(x) = foo() else { continue };
569+
}
570+
}
571+
"#,
572+
);
573+
}
574+
453575
#[test]
454576
fn convert_arbitrary_if_let_patterns() {
455577
check_assist(

0 commit comments

Comments
 (0)