ide_assists/handlers/
convert_to_guarded_return.rs

1use std::iter::once;
2
3use either::Either;
4use hir::{Semantics, TypeInfo};
5use ide_db::{RootDatabase, ty_filter::TryEnum};
6use syntax::{
7    AstNode,
8    SyntaxKind::{CLOSURE_EXPR, FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
9    SyntaxNode, T,
10    ast::{
11        self,
12        edit::{AstNodeEdit, IndentLevel},
13        make,
14    },
15};
16
17use crate::{
18    AssistId,
19    assist_context::{AssistContext, Assists},
20    utils::{invert_boolean_expression_legacy, is_never_block},
21};
22
23// Assist: convert_to_guarded_return
24//
25// Replace a large conditional with a guarded return.
26//
27// ```
28// fn main() {
29//     $0if cond {
30//         foo();
31//         bar();
32//     }
33// }
34// ```
35// ->
36// ```
37// fn main() {
38//     if !cond {
39//         return;
40//     }
41//     foo();
42//     bar();
43// }
44// ```
45pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
46    match ctx.find_node_at_offset::<Either<ast::LetStmt, ast::IfExpr>>()? {
47        Either::Left(let_stmt) => let_stmt_to_guarded_return(let_stmt, acc, ctx),
48        Either::Right(if_expr) => if_expr_to_guarded_return(if_expr, acc, ctx),
49    }
50}
51
52fn if_expr_to_guarded_return(
53    if_expr: ast::IfExpr,
54    acc: &mut Assists,
55    ctx: &AssistContext<'_>,
56) -> Option<()> {
57    let else_block = match if_expr.else_branch() {
58        Some(ast::ElseBranch::Block(block_expr)) if is_never_block(&ctx.sema, &block_expr) => {
59            Some(block_expr)
60        }
61        Some(_) => return None,
62        _ => None,
63    };
64
65    let cond = if_expr.condition()?;
66
67    let if_token_range = if_expr.if_token()?.text_range();
68    let if_cond_range = cond.syntax().text_range();
69
70    let cursor_in_range =
71        if_token_range.cover(if_cond_range).contains_range(ctx.selection_trimmed());
72    if !cursor_in_range {
73        return None;
74    }
75
76    let let_chains = flat_let_chain(cond);
77
78    let then_branch = if_expr.then_branch()?;
79    let then_block = then_branch.stmt_list()?;
80
81    let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
82
83    if parent_block.tail_expr()? != if_expr.clone().into() {
84        return None;
85    }
86
87    // check for early return and continue
88    if is_early_block(&then_block) || is_never_block(&ctx.sema, &then_branch) {
89        return None;
90    }
91
92    let parent_container = parent_block.syntax().parent()?;
93
94    let early_expression = else_block
95        .or_else(|| {
96            early_expression(parent_container, &ctx.sema).map(ast::make::tail_only_block_expr)
97        })?
98        .reset_indent();
99
100    then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?;
101
102    then_block.syntax().last_child_or_token().filter(|t| t.kind() == T!['}'])?;
103
104    let then_block_items = then_block.dedent(IndentLevel(1));
105
106    let end_of_then = then_block_items.syntax().last_child_or_token()?;
107    let end_of_then = if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
108        end_of_then.prev_sibling_or_token()?
109    } else {
110        end_of_then
111    };
112
113    let target = if_expr.syntax().text_range();
114    acc.add(
115        AssistId::refactor_rewrite("convert_to_guarded_return"),
116        "Convert to guarded return",
117        target,
118        |edit| {
119            let if_indent_level = IndentLevel::from_node(if_expr.syntax());
120            let replacement = let_chains.into_iter().map(|expr| {
121                if let ast::Expr::LetExpr(let_expr) = &expr
122                    && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr())
123                {
124                    // If-let.
125                    let let_else_stmt =
126                        make::let_else_stmt(pat, None, expr, early_expression.clone());
127                    let let_else_stmt = let_else_stmt.indent(if_indent_level);
128                    let_else_stmt.syntax().clone()
129                } else {
130                    // If.
131                    let new_expr = {
132                        let then_branch = clean_stmt_block(&early_expression);
133                        let cond = invert_boolean_expression_legacy(expr);
134                        make::expr_if(cond, then_branch, None).indent(if_indent_level)
135                    };
136                    new_expr.syntax().clone()
137                }
138            });
139
140            let newline = &format!("\n{if_indent_level}");
141            let then_statements = replacement
142                .enumerate()
143                .flat_map(|(i, node)| {
144                    (i != 0)
145                        .then(|| make::tokens::whitespace(newline).into())
146                        .into_iter()
147                        .chain(node.children_with_tokens())
148                })
149                .chain(
150                    then_block_items
151                        .syntax()
152                        .children_with_tokens()
153                        .skip(1)
154                        .take_while(|i| *i != end_of_then),
155                )
156                .collect();
157            let mut editor = edit.make_editor(if_expr.syntax());
158            editor.replace_with_many(if_expr.syntax(), then_statements);
159            edit.add_file_edits(ctx.vfs_file_id(), editor);
160        },
161    )
162}
163
164fn let_stmt_to_guarded_return(
165    let_stmt: ast::LetStmt,
166    acc: &mut Assists,
167    ctx: &AssistContext<'_>,
168) -> Option<()> {
169    let pat = let_stmt.pat()?;
170    let expr = let_stmt.initializer()?;
171
172    let let_token_range = let_stmt.let_token()?.text_range();
173    let let_pattern_range = pat.syntax().text_range();
174    let cursor_in_range =
175        let_token_range.cover(let_pattern_range).contains_range(ctx.selection_trimmed());
176
177    if !cursor_in_range || let_stmt.let_else().is_some() {
178        return None;
179    }
180
181    let try_enum =
182        ctx.sema.type_of_expr(&expr).and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))?;
183
184    let happy_pattern = try_enum.happy_pattern(pat);
185    let target = let_stmt.syntax().text_range();
186
187    let early_expression: ast::Expr = {
188        let parent_block =
189            let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
190        let parent_container = parent_block.syntax().parent()?;
191
192        early_expression(parent_container, &ctx.sema)?
193    };
194
195    acc.add(
196        AssistId::refactor_rewrite("convert_to_guarded_return"),
197        "Convert to guarded return",
198        target,
199        |edit| {
200            let let_indent_level = IndentLevel::from_node(let_stmt.syntax());
201
202            let replacement = {
203                let let_else_stmt = make::let_else_stmt(
204                    happy_pattern,
205                    let_stmt.ty(),
206                    expr,
207                    ast::make::tail_only_block_expr(early_expression),
208                );
209                let let_else_stmt = let_else_stmt.indent(let_indent_level);
210                let_else_stmt.syntax().clone()
211            };
212            let mut editor = edit.make_editor(let_stmt.syntax());
213            editor.replace(let_stmt.syntax(), replacement);
214            edit.add_file_edits(ctx.vfs_file_id(), editor);
215        },
216    )
217}
218
219fn early_expression(
220    parent_container: SyntaxNode,
221    sema: &Semantics<'_, RootDatabase>,
222) -> Option<ast::Expr> {
223    let return_none_expr = || {
224        let none_expr = make::expr_path(make::ext::ident_path("None"));
225        make::expr_return(Some(none_expr))
226    };
227    if let Some(fn_) = ast::Fn::cast(parent_container.clone())
228        && let Some(fn_def) = sema.to_def(&fn_)
229        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db))
230    {
231        return Some(return_none_expr());
232    }
233    if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body())
234        && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original)
235        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty)
236    {
237        return Some(return_none_expr());
238    }
239
240    Some(match parent_container.kind() {
241        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
242        FN | CLOSURE_EXPR => make::expr_return(None),
243        _ => return None,
244    })
245}
246
247fn flat_let_chain(mut expr: ast::Expr) -> Vec<ast::Expr> {
248    let mut chains = vec![];
249    let mut reduce_cond = |rhs| {
250        if !matches!(rhs, ast::Expr::LetExpr(_))
251            && let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_)))
252        {
253            chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
254        } else {
255            chains.push(rhs);
256        }
257    };
258
259    while let ast::Expr::BinExpr(bin_expr) = &expr
260        && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
261        && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs())
262    {
263        reduce_cond(rhs);
264        expr = lhs;
265    }
266
267    reduce_cond(expr);
268    chains.reverse();
269    chains
270}
271
272fn clean_stmt_block(block: &ast::BlockExpr) -> ast::BlockExpr {
273    if block.statements().next().is_none()
274        && let Some(tail_expr) = block.tail_expr()
275        && block.modifier().is_none()
276    {
277        make::block_expr(once(make::expr_stmt(tail_expr).into()), None)
278    } else {
279        block.clone()
280    }
281}
282
283fn is_early_block(then_block: &ast::StmtList) -> bool {
284    let is_early_expr =
285        |expr| matches!(expr, ast::Expr::ReturnExpr(_) | ast::Expr::ContinueExpr(_));
286    let into_expr = |stmt| match stmt {
287        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr(),
288        _ => None,
289    };
290    then_block.tail_expr().is_some_and(is_early_expr)
291        || then_block.statements().filter_map(into_expr).any(is_early_expr)
292}
293
294#[cfg(test)]
295mod tests {
296    use crate::tests::{check_assist, check_assist_not_applicable};
297
298    use super::*;
299
300    #[test]
301    fn convert_inside_fn() {
302        check_assist(
303            convert_to_guarded_return,
304            r#"
305fn main() {
306    bar();
307    if$0 true {
308        foo();
309
310        // comment
311        bar();
312    }
313}
314"#,
315            r#"
316fn main() {
317    bar();
318    if false {
319        return;
320    }
321    foo();
322
323    // comment
324    bar();
325}
326"#,
327        );
328    }
329
330    #[test]
331    fn convert_inside_fn_return_option() {
332        check_assist(
333            convert_to_guarded_return,
334            r#"
335//- minicore: option
336fn ret_option() -> Option<()> {
337    bar();
338    if$0 true {
339        foo();
340
341        // comment
342        bar();
343    }
344}
345"#,
346            r#"
347fn ret_option() -> Option<()> {
348    bar();
349    if false {
350        return None;
351    }
352    foo();
353
354    // comment
355    bar();
356}
357"#,
358        );
359    }
360
361    #[test]
362    fn convert_inside_closure() {
363        check_assist(
364            convert_to_guarded_return,
365            r#"
366fn main() {
367    let _f = || {
368        bar();
369        if$0 true {
370            foo();
371
372            // comment
373            bar();
374        }
375    }
376}
377"#,
378            r#"
379fn main() {
380    let _f = || {
381        bar();
382        if false {
383            return;
384        }
385        foo();
386
387        // comment
388        bar();
389    }
390}
391"#,
392        );
393    }
394
395    #[test]
396    fn convert_let_inside_fn() {
397        check_assist(
398            convert_to_guarded_return,
399            r#"
400fn main(n: Option<String>) {
401    bar();
402    if$0 let Some(n) = n {
403        foo(n);
404
405        // comment
406        bar();
407    }
408}
409"#,
410            r#"
411fn main(n: Option<String>) {
412    bar();
413    let Some(n) = n else { return };
414    foo(n);
415
416    // comment
417    bar();
418}
419"#,
420        );
421    }
422
423    #[test]
424    fn convert_if_let_result() {
425        check_assist(
426            convert_to_guarded_return,
427            r#"
428fn main() {
429    if$0 let Ok(x) = Err(92) {
430        foo(x);
431    }
432}
433"#,
434            r#"
435fn main() {
436    let Ok(x) = Err(92) else { return };
437    foo(x);
438}
439"#,
440        );
441    }
442
443    #[test]
444    fn convert_if_let_has_never_type_else_block() {
445        check_assist(
446            convert_to_guarded_return,
447            r#"
448fn main() {
449    if$0 let Ok(x) = Err(92) {
450        foo(x);
451    } else {
452        // needless comment
453        return;
454    }
455}
456"#,
457            r#"
458fn main() {
459    let Ok(x) = Err(92) else {
460        // needless comment
461        return;
462    };
463    foo(x);
464}
465"#,
466        );
467
468        check_assist(
469            convert_to_guarded_return,
470            r#"
471fn main() {
472    if$0 let Ok(x) = Err(92) {
473        foo(x);
474    } else {
475        return
476    }
477}
478"#,
479            r#"
480fn main() {
481    let Ok(x) = Err(92) else {
482        return
483    };
484    foo(x);
485}
486"#,
487        );
488    }
489
490    #[test]
491    fn convert_if_let_result_inside_let() {
492        check_assist(
493            convert_to_guarded_return,
494            r#"
495fn main() {
496    let _x = loop {
497        if$0 let Ok(x) = Err(92) {
498            foo(x);
499        }
500    };
501}
502"#,
503            r#"
504fn main() {
505    let _x = loop {
506        let Ok(x) = Err(92) else { continue };
507        foo(x);
508    };
509}
510"#,
511        );
512    }
513
514    #[test]
515    fn convert_if_let_chain_result() {
516        check_assist(
517            convert_to_guarded_return,
518            r#"
519fn main() {
520    if$0 let Ok(x) = Err(92)
521        && x < 30
522        && let Some(y) = Some(8)
523    {
524        foo(x, y);
525    }
526}
527"#,
528            r#"
529fn main() {
530    let Ok(x) = Err(92) else { return };
531    if x >= 30 {
532        return;
533    }
534    let Some(y) = Some(8) else { return };
535    foo(x, y);
536}
537"#,
538        );
539
540        check_assist(
541            convert_to_guarded_return,
542            r#"
543fn main() {
544    if$0 let Ok(x) = Err(92)
545        && x < 30
546        && y < 20
547        && let Some(y) = Some(8)
548    {
549        foo(x, y);
550    }
551}
552"#,
553            r#"
554fn main() {
555    let Ok(x) = Err(92) else { return };
556    if !(x < 30 && y < 20) {
557        return;
558    }
559    let Some(y) = Some(8) else { return };
560    foo(x, y);
561}
562"#,
563        );
564
565        check_assist(
566            convert_to_guarded_return,
567            r#"
568fn main() {
569    if$0 let Ok(x) = Err(92)
570        && let Ok(y) = Ok(37)
571        && x < 30
572        && let Some(y) = Some(8)
573    {
574        foo(x, y);
575    }
576}
577"#,
578            r#"
579fn main() {
580    let Ok(x) = Err(92) else { return };
581    let Ok(y) = Ok(37) else { return };
582    if x >= 30 {
583        return;
584    }
585    let Some(y) = Some(8) else { return };
586    foo(x, y);
587}
588"#,
589        );
590
591        check_assist(
592            convert_to_guarded_return,
593            r#"
594fn main() {
595    if$0 cond
596        && let Ok(x) = Err(92)
597        && let Ok(y) = Ok(37)
598        && x < 30
599        && let Some(y) = Some(8)
600    {
601        foo(x, y);
602    }
603}
604"#,
605            r#"
606fn main() {
607    if !cond {
608        return;
609    }
610    let Ok(x) = Err(92) else { return };
611    let Ok(y) = Ok(37) else { return };
612    if x >= 30 {
613        return;
614    }
615    let Some(y) = Some(8) else { return };
616    foo(x, y);
617}
618"#,
619        );
620
621        check_assist(
622            convert_to_guarded_return,
623            r#"
624fn main() {
625    if$0 cond
626        && foo()
627        && let Ok(x) = Err(92)
628        && let Ok(y) = Ok(37)
629        && x < 30
630        && let Some(y) = Some(8)
631    {
632        foo(x, y);
633    }
634}
635"#,
636            r#"
637fn main() {
638    if !(cond && foo()) {
639        return;
640    }
641    let Ok(x) = Err(92) else { return };
642    let Ok(y) = Ok(37) else { return };
643    if x >= 30 {
644        return;
645    }
646    let Some(y) = Some(8) else { return };
647    foo(x, y);
648}
649"#,
650        );
651    }
652
653    #[test]
654    fn convert_let_ok_inside_fn() {
655        check_assist(
656            convert_to_guarded_return,
657            r#"
658fn main(n: Option<String>) {
659    bar();
660    if$0 let Some(n) = n {
661        foo(n);
662
663        // comment
664        bar();
665    }
666}
667"#,
668            r#"
669fn main(n: Option<String>) {
670    bar();
671    let Some(n) = n else { return };
672    foo(n);
673
674    // comment
675    bar();
676}
677"#,
678        );
679    }
680
681    #[test]
682    fn convert_let_mut_ok_inside_fn() {
683        check_assist(
684            convert_to_guarded_return,
685            r#"
686fn main(n: Option<String>) {
687    bar();
688    if$0 let Some(mut n) = n {
689        foo(n);
690
691        // comment
692        bar();
693    }
694}
695"#,
696            r#"
697fn main(n: Option<String>) {
698    bar();
699    let Some(mut n) = n else { return };
700    foo(n);
701
702    // comment
703    bar();
704}
705"#,
706        );
707    }
708
709    #[test]
710    fn convert_let_ref_ok_inside_fn() {
711        check_assist(
712            convert_to_guarded_return,
713            r#"
714fn main(n: Option<&str>) {
715    bar();
716    if$0 let Some(ref n) = n {
717        foo(n);
718
719        // comment
720        bar();
721    }
722}
723"#,
724            r#"
725fn main(n: Option<&str>) {
726    bar();
727    let Some(ref n) = n else { return };
728    foo(n);
729
730    // comment
731    bar();
732}
733"#,
734        );
735    }
736
737    #[test]
738    fn convert_inside_while() {
739        check_assist(
740            convert_to_guarded_return,
741            r#"
742fn main() {
743    while true {
744        if$0 true {
745            foo();
746            bar();
747        }
748    }
749}
750"#,
751            r#"
752fn main() {
753    while true {
754        if false {
755            continue;
756        }
757        foo();
758        bar();
759    }
760}
761"#,
762        );
763    }
764
765    #[test]
766    fn convert_let_inside_while() {
767        check_assist(
768            convert_to_guarded_return,
769            r#"
770fn main() {
771    while true {
772        if$0 let Some(n) = n {
773            foo(n);
774            bar();
775        }
776    }
777}
778"#,
779            r#"
780fn main() {
781    while true {
782        let Some(n) = n else { continue };
783        foo(n);
784        bar();
785    }
786}
787"#,
788        );
789    }
790
791    #[test]
792    fn convert_inside_loop() {
793        check_assist(
794            convert_to_guarded_return,
795            r#"
796fn main() {
797    loop {
798        if$0 true {
799            foo();
800            bar();
801        }
802    }
803}
804"#,
805            r#"
806fn main() {
807    loop {
808        if false {
809            continue;
810        }
811        foo();
812        bar();
813    }
814}
815"#,
816        );
817    }
818
819    #[test]
820    fn convert_let_inside_loop() {
821        check_assist(
822            convert_to_guarded_return,
823            r#"
824fn main() {
825    loop {
826        if$0 let Some(n) = n {
827            foo(n);
828            bar();
829        }
830    }
831}
832"#,
833            r#"
834fn main() {
835    loop {
836        let Some(n) = n else { continue };
837        foo(n);
838        bar();
839    }
840}
841"#,
842        );
843    }
844
845    #[test]
846    fn convert_let_inside_for() {
847        check_assist(
848            convert_to_guarded_return,
849            r#"
850fn main() {
851    for n in ns {
852        if$0 let Some(n) = n {
853            foo(n);
854            bar();
855        }
856    }
857}
858"#,
859            r#"
860fn main() {
861    for n in ns {
862        let Some(n) = n else { continue };
863        foo(n);
864        bar();
865    }
866}
867"#,
868        );
869    }
870
871    #[test]
872    fn convert_let_stmt_inside_fn() {
873        check_assist(
874            convert_to_guarded_return,
875            r#"
876//- minicore: option
877fn foo() -> Option<i32> {
878    None
879}
880
881fn main() {
882    let x$0 = foo();
883}
884"#,
885            r#"
886fn foo() -> Option<i32> {
887    None
888}
889
890fn main() {
891    let Some(x) = foo() else { return };
892}
893"#,
894        );
895    }
896
897    #[test]
898    fn convert_let_stmt_inside_fn_return_option() {
899        check_assist(
900            convert_to_guarded_return,
901            r#"
902//- minicore: option
903fn foo() -> Option<i32> {
904    None
905}
906
907fn ret_option() -> Option<i32> {
908    let x$0 = foo();
909}
910"#,
911            r#"
912fn foo() -> Option<i32> {
913    None
914}
915
916fn ret_option() -> Option<i32> {
917    let Some(x) = foo() else { return None };
918}
919"#,
920        );
921    }
922
923    #[test]
924    fn convert_let_stmt_inside_loop() {
925        check_assist(
926            convert_to_guarded_return,
927            r#"
928//- minicore: option
929fn foo() -> Option<i32> {
930    None
931}
932
933fn main() {
934    loop {
935        let x$0 = foo();
936    }
937}
938"#,
939            r#"
940fn foo() -> Option<i32> {
941    None
942}
943
944fn main() {
945    loop {
946        let Some(x) = foo() else { continue };
947    }
948}
949"#,
950        );
951    }
952
953    #[test]
954    fn convert_arbitrary_if_let_patterns() {
955        check_assist(
956            convert_to_guarded_return,
957            r#"
958fn main() {
959    $0if let None = Some(92) {
960        foo();
961    }
962}
963"#,
964            r#"
965fn main() {
966    let None = Some(92) else { return };
967    foo();
968}
969"#,
970        );
971
972        check_assist(
973            convert_to_guarded_return,
974            r#"
975fn main() {
976    $0if let [1, x] = [1, 92] {
977        foo(x);
978    }
979}
980"#,
981            r#"
982fn main() {
983    let [1, x] = [1, 92] else { return };
984    foo(x);
985}
986"#,
987        );
988
989        check_assist(
990            convert_to_guarded_return,
991            r#"
992fn main() {
993    $0if let (Some(x), None) = (Some(92), None) {
994        foo(x);
995    }
996}
997"#,
998            r#"
999fn main() {
1000    let (Some(x), None) = (Some(92), None) else { return };
1001    foo(x);
1002}
1003"#,
1004        );
1005    }
1006
1007    #[test]
1008    fn ignore_already_converted_if() {
1009        check_assist_not_applicable(
1010            convert_to_guarded_return,
1011            r#"
1012fn main() {
1013    if$0 true {
1014        return;
1015    }
1016}
1017"#,
1018        );
1019    }
1020
1021    #[test]
1022    fn ignore_already_converted_loop() {
1023        check_assist_not_applicable(
1024            convert_to_guarded_return,
1025            r#"
1026fn main() {
1027    loop {
1028        if$0 true {
1029            continue;
1030        }
1031    }
1032}
1033"#,
1034        );
1035    }
1036
1037    #[test]
1038    fn ignore_return() {
1039        check_assist_not_applicable(
1040            convert_to_guarded_return,
1041            r#"
1042fn main() {
1043    if$0 true {
1044        return
1045    }
1046}
1047"#,
1048        );
1049    }
1050
1051    #[test]
1052    fn ignore_else_branch() {
1053        check_assist_not_applicable(
1054            convert_to_guarded_return,
1055            r#"
1056fn main() {
1057    if$0 true {
1058        foo();
1059    } else {
1060        bar()
1061    }
1062}
1063"#,
1064        );
1065    }
1066
1067    #[test]
1068    fn ignore_let_else_branch() {
1069        check_assist_not_applicable(
1070            convert_to_guarded_return,
1071            r#"
1072//- minicore: option
1073fn main() {
1074    let$0 Some(x) = Some(2) else { return };
1075}
1076"#,
1077        );
1078    }
1079
1080    #[test]
1081    fn ignore_statements_after_if() {
1082        check_assist_not_applicable(
1083            convert_to_guarded_return,
1084            r#"
1085fn main() {
1086    if$0 true {
1087        foo();
1088    }
1089    bar();
1090}
1091"#,
1092        );
1093    }
1094
1095    #[test]
1096    fn ignore_statements_inside_if() {
1097        check_assist_not_applicable(
1098            convert_to_guarded_return,
1099            r#"
1100fn main() {
1101    if false {
1102        if$0 true {
1103            foo();
1104        }
1105    }
1106}
1107"#,
1108        );
1109    }
1110
1111    #[test]
1112    fn ignore_inside_if_stmt() {
1113        check_assist_not_applicable(
1114            convert_to_guarded_return,
1115            r#"
1116fn main() {
1117    if false {
1118        foo()$0;
1119    }
1120}
1121"#,
1122        );
1123    }
1124
1125    #[test]
1126    fn ignore_inside_let_initializer() {
1127        check_assist_not_applicable(
1128            convert_to_guarded_return,
1129            r#"
1130//- minicore: option
1131fn foo() -> Option<i32> {
1132    None
1133}
1134
1135fn main() {
1136    let x = foo()$0;
1137}
1138"#,
1139        );
1140    }
1141}