]> git.lizzy.rs Git - rust.git/blob - crates/ra_assists/src/handlers/change_return_type_to_result.rs
Refactor assists API to be more convenient for adding new assists
[rust.git] / crates / ra_assists / src / handlers / change_return_type_to_result.rs
1 use ra_syntax::{
2     ast::{self, BlockExpr, Expr, LoopBodyOwner},
3     AstNode,
4     SyntaxKind::{COMMENT, WHITESPACE},
5     SyntaxNode, TextSize,
6 };
7
8 use crate::{AssistContext, AssistId, Assists};
9
10 // Assist: change_return_type_to_result
11 //
12 // Change the function's return type to Result.
13 //
14 // ```
15 // fn foo() -> i32<|> { 42i32 }
16 // ```
17 // ->
18 // ```
19 // fn foo() -> Result<i32, > { Ok(42i32) }
20 // ```
21 pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
22     let fn_def = ctx.find_node_at_offset::<ast::FnDef>();
23     let fn_def = &mut fn_def?;
24     let ret_type = &fn_def.ret_type()?.type_ref()?;
25     if ret_type.syntax().text().to_string().starts_with("Result<") {
26         return None;
27     }
28
29     let block_expr = &fn_def.body()?;
30     let cursor_in_ret_type =
31         fn_def.ret_type()?.syntax().text_range().contains_range(ctx.frange.range);
32     if !cursor_in_ret_type {
33         return None;
34     }
35
36     acc.add(
37         AssistId("change_return_type_to_result"),
38         "Change return type to Result",
39         ret_type.syntax().text_range(),
40         |edit| {
41             let mut tail_return_expr_collector = TailReturnCollector::new();
42             tail_return_expr_collector.collect_jump_exprs(block_expr, false);
43             tail_return_expr_collector.collect_tail_exprs(block_expr);
44
45             for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap {
46                 edit.replace_node_and_indent(&ret_expr_arg, format!("Ok({})", ret_expr_arg));
47             }
48             edit.replace_node_and_indent(ret_type.syntax(), format!("Result<{}, >", ret_type));
49
50             if let Some(node_start) = result_insertion_offset(&ret_type) {
51                 edit.set_cursor(node_start + TextSize::of(&format!("Result<{}, ", ret_type)));
52             }
53         },
54     )
55 }
56
57 struct TailReturnCollector {
58     exprs_to_wrap: Vec<SyntaxNode>,
59 }
60
61 impl TailReturnCollector {
62     fn new() -> Self {
63         Self { exprs_to_wrap: vec![] }
64     }
65     /// Collect all`return` expression
66     fn collect_jump_exprs(&mut self, block_expr: &BlockExpr, collect_break: bool) {
67         let statements = block_expr.statements();
68         for stmt in statements {
69             let expr = match &stmt {
70                 ast::Stmt::ExprStmt(stmt) => stmt.expr(),
71                 ast::Stmt::LetStmt(stmt) => stmt.initializer(),
72             };
73             if let Some(expr) = &expr {
74                 self.handle_exprs(expr, collect_break);
75             }
76         }
77
78         // Browse tail expressions for each block
79         if let Some(expr) = block_expr.expr() {
80             if let Some(last_exprs) = get_tail_expr_from_block(&expr) {
81                 for last_expr in last_exprs {
82                     let last_expr = match last_expr {
83                         NodeType::Node(expr) | NodeType::Leaf(expr) => expr,
84                     };
85
86                     if let Some(last_expr) = Expr::cast(last_expr.clone()) {
87                         self.handle_exprs(&last_expr, collect_break);
88                     } else if let Some(expr_stmt) = ast::Stmt::cast(last_expr) {
89                         let expr_stmt = match &expr_stmt {
90                             ast::Stmt::ExprStmt(stmt) => stmt.expr(),
91                             ast::Stmt::LetStmt(stmt) => stmt.initializer(),
92                         };
93                         if let Some(expr) = &expr_stmt {
94                             self.handle_exprs(expr, collect_break);
95                         }
96                     }
97                 }
98             }
99         }
100     }
101
102     fn handle_exprs(&mut self, expr: &Expr, collect_break: bool) {
103         match expr {
104             Expr::BlockExpr(block_expr) => {
105                 self.collect_jump_exprs(&block_expr, collect_break);
106             }
107             Expr::ReturnExpr(ret_expr) => {
108                 if let Some(ret_expr_arg) = &ret_expr.expr() {
109                     self.exprs_to_wrap.push(ret_expr_arg.syntax().clone());
110                 }
111             }
112             Expr::BreakExpr(break_expr) if collect_break => {
113                 if let Some(break_expr_arg) = &break_expr.expr() {
114                     self.exprs_to_wrap.push(break_expr_arg.syntax().clone());
115                 }
116             }
117             Expr::IfExpr(if_expr) => {
118                 for block in if_expr.blocks() {
119                     self.collect_jump_exprs(&block, collect_break);
120                 }
121             }
122             Expr::LoopExpr(loop_expr) => {
123                 if let Some(block_expr) = loop_expr.loop_body() {
124                     self.collect_jump_exprs(&block_expr, collect_break);
125                 }
126             }
127             Expr::ForExpr(for_expr) => {
128                 if let Some(block_expr) = for_expr.loop_body() {
129                     self.collect_jump_exprs(&block_expr, collect_break);
130                 }
131             }
132             Expr::WhileExpr(while_expr) => {
133                 if let Some(block_expr) = while_expr.loop_body() {
134                     self.collect_jump_exprs(&block_expr, collect_break);
135                 }
136             }
137             Expr::MatchExpr(match_expr) => {
138                 if let Some(arm_list) = match_expr.match_arm_list() {
139                     arm_list.arms().filter_map(|match_arm| match_arm.expr()).for_each(|expr| {
140                         self.handle_exprs(&expr, collect_break);
141                     });
142                 }
143             }
144             _ => {}
145         }
146     }
147
148     fn collect_tail_exprs(&mut self, block: &BlockExpr) {
149         if let Some(expr) = block.expr() {
150             self.handle_exprs(&expr, true);
151             self.fetch_tail_exprs(&expr);
152         }
153     }
154
155     fn fetch_tail_exprs(&mut self, expr: &Expr) {
156         if let Some(exprs) = get_tail_expr_from_block(expr) {
157             for node_type in &exprs {
158                 match node_type {
159                     NodeType::Leaf(expr) => {
160                         self.exprs_to_wrap.push(expr.clone());
161                     }
162                     NodeType::Node(expr) => match &Expr::cast(expr.clone()) {
163                         Some(last_expr) => {
164                             self.fetch_tail_exprs(last_expr);
165                         }
166                         None => {
167                             self.exprs_to_wrap.push(expr.clone());
168                         }
169                     },
170                 }
171             }
172         }
173     }
174 }
175
176 #[derive(Debug)]
177 enum NodeType {
178     Leaf(SyntaxNode),
179     Node(SyntaxNode),
180 }
181
182 /// Get a tail expression inside a block
183 fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> {
184     match expr {
185         Expr::IfExpr(if_expr) => {
186             let mut nodes = vec![];
187             for block in if_expr.blocks() {
188                 if let Some(block_expr) = block.expr() {
189                     if let Some(tail_exprs) = get_tail_expr_from_block(&block_expr) {
190                         nodes.extend(tail_exprs);
191                     }
192                 } else if let Some(last_expr) = block.syntax().last_child() {
193                     nodes.push(NodeType::Node(last_expr));
194                 } else {
195                     nodes.push(NodeType::Node(block.syntax().clone()));
196                 }
197             }
198             Some(nodes)
199         }
200         Expr::LoopExpr(loop_expr) => {
201             loop_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)])
202         }
203         Expr::ForExpr(for_expr) => {
204             for_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)])
205         }
206         Expr::WhileExpr(while_expr) => {
207             while_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)])
208         }
209         Expr::BlockExpr(block_expr) => {
210             block_expr.expr().map(|lc| vec![NodeType::Node(lc.syntax().clone())])
211         }
212         Expr::MatchExpr(match_expr) => {
213             let arm_list = match_expr.match_arm_list()?;
214             let arms: Vec<NodeType> = arm_list
215                 .arms()
216                 .filter_map(|match_arm| match_arm.expr())
217                 .map(|expr| match expr {
218                     Expr::ReturnExpr(ret_expr) => NodeType::Node(ret_expr.syntax().clone()),
219                     Expr::BreakExpr(break_expr) => NodeType::Node(break_expr.syntax().clone()),
220                     _ => match expr.syntax().last_child() {
221                         Some(last_expr) => NodeType::Node(last_expr),
222                         None => NodeType::Node(expr.syntax().clone()),
223                     },
224                 })
225                 .collect();
226
227             Some(arms)
228         }
229         Expr::BreakExpr(expr) => expr.expr().map(|e| vec![NodeType::Leaf(e.syntax().clone())]),
230         Expr::ReturnExpr(ret_expr) => Some(vec![NodeType::Node(ret_expr.syntax().clone())]),
231         Expr::CallExpr(call_expr) => Some(vec![NodeType::Leaf(call_expr.syntax().clone())]),
232         Expr::Literal(lit_expr) => Some(vec![NodeType::Leaf(lit_expr.syntax().clone())]),
233         Expr::TupleExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
234         Expr::ArrayExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
235         Expr::ParenExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
236         Expr::PathExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
237         Expr::Label(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
238         Expr::RecordLit(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
239         Expr::IndexExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
240         Expr::MethodCallExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
241         Expr::AwaitExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
242         Expr::CastExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
243         Expr::RefExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
244         Expr::PrefixExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
245         Expr::RangeExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
246         Expr::BinExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
247         Expr::MacroCall(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
248         Expr::BoxExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
249         _ => None,
250     }
251 }
252
253 fn result_insertion_offset(ret_type: &ast::TypeRef) -> Option<TextSize> {
254     let non_ws_child = ret_type
255         .syntax()
256         .children_with_tokens()
257         .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
258     Some(non_ws_child.text_range().start())
259 }
260
261 #[cfg(test)]
262 mod tests {
263
264     use crate::tests::{check_assist, check_assist_not_applicable};
265
266     use super::*;
267
268     #[test]
269     fn change_return_type_to_result_simple() {
270         check_assist(
271             change_return_type_to_result,
272             r#"fn foo() -> i3<|>2 {
273                 let test = "test";
274                 return 42i32;
275             }"#,
276             r#"fn foo() -> Result<i32, <|>> {
277                 let test = "test";
278                 return Ok(42i32);
279             }"#,
280         );
281     }
282
283     #[test]
284     fn change_return_type_to_result_simple_return_type() {
285         check_assist(
286             change_return_type_to_result,
287             r#"fn foo() -> i32<|> {
288                 let test = "test";
289                 return 42i32;
290             }"#,
291             r#"fn foo() -> Result<i32, <|>> {
292                 let test = "test";
293                 return Ok(42i32);
294             }"#,
295         );
296     }
297
298     #[test]
299     fn change_return_type_to_result_simple_return_type_bad_cursor() {
300         check_assist_not_applicable(
301             change_return_type_to_result,
302             r#"fn foo() -> i32 {
303                 let test = "test";<|>
304                 return 42i32;
305             }"#,
306         );
307     }
308
309     #[test]
310     fn change_return_type_to_result_simple_with_cursor() {
311         check_assist(
312             change_return_type_to_result,
313             r#"fn foo() -> <|>i32 {
314                 let test = "test";
315                 return 42i32;
316             }"#,
317             r#"fn foo() -> Result<i32, <|>> {
318                 let test = "test";
319                 return Ok(42i32);
320             }"#,
321         );
322     }
323
324     #[test]
325     fn change_return_type_to_result_simple_with_tail() {
326         check_assist(
327             change_return_type_to_result,
328             r#"fn foo() -><|> i32 {
329                 let test = "test";
330                 42i32
331             }"#,
332             r#"fn foo() -> Result<i32, <|>> {
333                 let test = "test";
334                 Ok(42i32)
335             }"#,
336         );
337     }
338
339     #[test]
340     fn change_return_type_to_result_simple_with_tail_only() {
341         check_assist(
342             change_return_type_to_result,
343             r#"fn foo() -> i32<|> {
344                 42i32
345             }"#,
346             r#"fn foo() -> Result<i32, <|>> {
347                 Ok(42i32)
348             }"#,
349         );
350     }
351     #[test]
352     fn change_return_type_to_result_simple_with_tail_block_like() {
353         check_assist(
354             change_return_type_to_result,
355             r#"fn foo() -> i32<|> {
356                 if true {
357                     42i32
358                 } else {
359                     24i32
360                 }
361             }"#,
362             r#"fn foo() -> Result<i32, <|>> {
363                 if true {
364                     Ok(42i32)
365                 } else {
366                     Ok(24i32)
367                 }
368             }"#,
369         );
370     }
371
372     #[test]
373     fn change_return_type_to_result_simple_with_nested_if() {
374         check_assist(
375             change_return_type_to_result,
376             r#"fn foo() -> i32<|> {
377                 if true {
378                     if false {
379                         1
380                     } else {
381                         2
382                     }
383                 } else {
384                     24i32
385                 }
386             }"#,
387             r#"fn foo() -> Result<i32, <|>> {
388                 if true {
389                     if false {
390                         Ok(1)
391                     } else {
392                         Ok(2)
393                     }
394                 } else {
395                     Ok(24i32)
396                 }
397             }"#,
398         );
399     }
400
401     #[test]
402     fn change_return_type_to_result_simple_with_await() {
403         check_assist(
404             change_return_type_to_result,
405             r#"async fn foo() -> i<|>32 {
406                 if true {
407                     if false {
408                         1.await
409                     } else {
410                         2.await
411                     }
412                 } else {
413                     24i32.await
414                 }
415             }"#,
416             r#"async fn foo() -> Result<i32, <|>> {
417                 if true {
418                     if false {
419                         Ok(1.await)
420                     } else {
421                         Ok(2.await)
422                     }
423                 } else {
424                     Ok(24i32.await)
425                 }
426             }"#,
427         );
428     }
429
430     #[test]
431     fn change_return_type_to_result_simple_with_array() {
432         check_assist(
433             change_return_type_to_result,
434             r#"fn foo() -> [i32;<|> 3] {
435                 [1, 2, 3]
436             }"#,
437             r#"fn foo() -> Result<[i32; 3], <|>> {
438                 Ok([1, 2, 3])
439             }"#,
440         );
441     }
442
443     #[test]
444     fn change_return_type_to_result_simple_with_cast() {
445         check_assist(
446             change_return_type_to_result,
447             r#"fn foo() -<|>> i32 {
448                 if true {
449                     if false {
450                         1 as i32
451                     } else {
452                         2 as i32
453                     }
454                 } else {
455                     24 as i32
456                 }
457             }"#,
458             r#"fn foo() -> Result<i32, <|>> {
459                 if true {
460                     if false {
461                         Ok(1 as i32)
462                     } else {
463                         Ok(2 as i32)
464                     }
465                 } else {
466                     Ok(24 as i32)
467                 }
468             }"#,
469         );
470     }
471
472     #[test]
473     fn change_return_type_to_result_simple_with_tail_block_like_match() {
474         check_assist(
475             change_return_type_to_result,
476             r#"fn foo() -> i32<|> {
477                 let my_var = 5;
478                 match my_var {
479                     5 => 42i32,
480                     _ => 24i32,
481                 }
482             }"#,
483             r#"fn foo() -> Result<i32, <|>> {
484                 let my_var = 5;
485                 match my_var {
486                     5 => Ok(42i32),
487                     _ => Ok(24i32),
488                 }
489             }"#,
490         );
491     }
492
493     #[test]
494     fn change_return_type_to_result_simple_with_loop_with_tail() {
495         check_assist(
496             change_return_type_to_result,
497             r#"fn foo() -> i32<|> {
498                 let my_var = 5;
499                 loop {
500                     println!("test");
501                     5
502                 }
503
504                 my_var
505             }"#,
506             r#"fn foo() -> Result<i32, <|>> {
507                 let my_var = 5;
508                 loop {
509                     println!("test");
510                     5
511                 }
512
513                 Ok(my_var)
514             }"#,
515         );
516     }
517
518     #[test]
519     fn change_return_type_to_result_simple_with_loop_in_let_stmt() {
520         check_assist(
521             change_return_type_to_result,
522             r#"fn foo() -> i32<|> {
523                 let my_var = let x = loop {
524                     break 1;
525                 };
526
527                 my_var
528             }"#,
529             r#"fn foo() -> Result<i32, <|>> {
530                 let my_var = let x = loop {
531                     break 1;
532                 };
533
534                 Ok(my_var)
535             }"#,
536         );
537     }
538
539     #[test]
540     fn change_return_type_to_result_simple_with_tail_block_like_match_return_expr() {
541         check_assist(
542             change_return_type_to_result,
543             r#"fn foo() -> i32<|> {
544                 let my_var = 5;
545                 let res = match my_var {
546                     5 => 42i32,
547                     _ => return 24i32,
548                 };
549
550                 res
551             }"#,
552             r#"fn foo() -> Result<i32, <|>> {
553                 let my_var = 5;
554                 let res = match my_var {
555                     5 => 42i32,
556                     _ => return Ok(24i32),
557                 };
558
559                 Ok(res)
560             }"#,
561         );
562
563         check_assist(
564             change_return_type_to_result,
565             r#"fn foo() -> i32<|> {
566                 let my_var = 5;
567                 let res = if my_var == 5 {
568                     42i32
569                 } else {
570                     return 24i32;
571                 };
572
573                 res
574             }"#,
575             r#"fn foo() -> Result<i32, <|>> {
576                 let my_var = 5;
577                 let res = if my_var == 5 {
578                     42i32
579                 } else {
580                     return Ok(24i32);
581                 };
582
583                 Ok(res)
584             }"#,
585         );
586     }
587
588     #[test]
589     fn change_return_type_to_result_simple_with_tail_block_like_match_deeper() {
590         check_assist(
591             change_return_type_to_result,
592             r#"fn foo() -> i32<|> {
593                 let my_var = 5;
594                 match my_var {
595                     5 => {
596                         if true {
597                             42i32
598                         } else {
599                             25i32
600                         }
601                     },
602                     _ => {
603                         let test = "test";
604                         if test == "test" {
605                             return bar();
606                         }
607                         53i32
608                     },
609                 }
610             }"#,
611             r#"fn foo() -> Result<i32, <|>> {
612                 let my_var = 5;
613                 match my_var {
614                     5 => {
615                         if true {
616                             Ok(42i32)
617                         } else {
618                             Ok(25i32)
619                         }
620                     },
621                     _ => {
622                         let test = "test";
623                         if test == "test" {
624                             return Ok(bar());
625                         }
626                         Ok(53i32)
627                     },
628                 }
629             }"#,
630         );
631     }
632
633     #[test]
634     fn change_return_type_to_result_simple_with_tail_block_like_early_return() {
635         check_assist(
636             change_return_type_to_result,
637             r#"fn foo() -> i<|>32 {
638                 let test = "test";
639                 if test == "test" {
640                     return 24i32;
641                 }
642                 53i32
643             }"#,
644             r#"fn foo() -> Result<i32, <|>> {
645                 let test = "test";
646                 if test == "test" {
647                     return Ok(24i32);
648                 }
649                 Ok(53i32)
650             }"#,
651         );
652     }
653
654     #[test]
655     fn change_return_type_to_result_simple_with_closure() {
656         check_assist(
657             change_return_type_to_result,
658             r#"fn foo(the_field: u32) -><|> u32 {
659                 let true_closure = || {
660                     return true;
661                 };
662                 if the_field < 5 {
663                     let mut i = 0;
664
665
666                     if true_closure() {
667                         return 99;
668                     } else {
669                         return 0;
670                     }
671                 }
672
673                 the_field
674             }"#,
675             r#"fn foo(the_field: u32) -> Result<u32, <|>> {
676                 let true_closure = || {
677                     return true;
678                 };
679                 if the_field < 5 {
680                     let mut i = 0;
681
682
683                     if true_closure() {
684                         return Ok(99);
685                     } else {
686                         return Ok(0);
687                     }
688                 }
689
690                 Ok(the_field)
691             }"#,
692         );
693
694         check_assist(
695             change_return_type_to_result,
696             r#"fn foo(the_field: u32) -> u32<|> {
697                 let true_closure = || {
698                     return true;
699                 };
700                 if the_field < 5 {
701                     let mut i = 0;
702
703
704                     if true_closure() {
705                         return 99;
706                     } else {
707                         return 0;
708                     }
709                 }
710                 let t = None;
711
712                 t.unwrap_or_else(|| the_field)
713             }"#,
714             r#"fn foo(the_field: u32) -> Result<u32, <|>> {
715                 let true_closure = || {
716                     return true;
717                 };
718                 if the_field < 5 {
719                     let mut i = 0;
720
721
722                     if true_closure() {
723                         return Ok(99);
724                     } else {
725                         return Ok(0);
726                     }
727                 }
728                 let t = None;
729
730                 Ok(t.unwrap_or_else(|| the_field))
731             }"#,
732         );
733     }
734
735     #[test]
736     fn change_return_type_to_result_simple_with_weird_forms() {
737         check_assist(
738             change_return_type_to_result,
739             r#"fn foo() -> i32<|> {
740                 let test = "test";
741                 if test == "test" {
742                     return 24i32;
743                 }
744                 let mut i = 0;
745                 loop {
746                     if i == 1 {
747                         break 55;
748                     }
749                     i += 1;
750                 }
751             }"#,
752             r#"fn foo() -> Result<i32, <|>> {
753                 let test = "test";
754                 if test == "test" {
755                     return Ok(24i32);
756                 }
757                 let mut i = 0;
758                 loop {
759                     if i == 1 {
760                         break Ok(55);
761                     }
762                     i += 1;
763                 }
764             }"#,
765         );
766
767         check_assist(
768             change_return_type_to_result,
769             r#"fn foo() -> i32<|> {
770                 let test = "test";
771                 if test == "test" {
772                     return 24i32;
773                 }
774                 let mut i = 0;
775                 loop {
776                     loop {
777                         if i == 1 {
778                             break 55;
779                         }
780                         i += 1;
781                     }
782                 }
783             }"#,
784             r#"fn foo() -> Result<i32, <|>> {
785                 let test = "test";
786                 if test == "test" {
787                     return Ok(24i32);
788                 }
789                 let mut i = 0;
790                 loop {
791                     loop {
792                         if i == 1 {
793                             break Ok(55);
794                         }
795                         i += 1;
796                     }
797                 }
798             }"#,
799         );
800
801         check_assist(
802             change_return_type_to_result,
803             r#"fn foo() -> i3<|>2 {
804                 let test = "test";
805                 let other = 5;
806                 if test == "test" {
807                     let res = match other {
808                         5 => 43,
809                         _ => return 56,
810                     };
811                 }
812                 let mut i = 0;
813                 loop {
814                     loop {
815                         if i == 1 {
816                             break 55;
817                         }
818                         i += 1;
819                     }
820                 }
821             }"#,
822             r#"fn foo() -> Result<i32, <|>> {
823                 let test = "test";
824                 let other = 5;
825                 if test == "test" {
826                     let res = match other {
827                         5 => 43,
828                         _ => return Ok(56),
829                     };
830                 }
831                 let mut i = 0;
832                 loop {
833                     loop {
834                         if i == 1 {
835                             break Ok(55);
836                         }
837                         i += 1;
838                     }
839                 }
840             }"#,
841         );
842
843         check_assist(
844             change_return_type_to_result,
845             r#"fn foo(the_field: u32) -> u32<|> {
846                 if the_field < 5 {
847                     let mut i = 0;
848                     loop {
849                         if i > 5 {
850                             return 55u32;
851                         }
852                         i += 3;
853                     }
854
855                     match i {
856                         5 => return 99,
857                         _ => return 0,
858                     };
859                 }
860
861                 the_field
862             }"#,
863             r#"fn foo(the_field: u32) -> Result<u32, <|>> {
864                 if the_field < 5 {
865                     let mut i = 0;
866                     loop {
867                         if i > 5 {
868                             return Ok(55u32);
869                         }
870                         i += 3;
871                     }
872
873                     match i {
874                         5 => return Ok(99),
875                         _ => return Ok(0),
876                     };
877                 }
878
879                 Ok(the_field)
880             }"#,
881         );
882
883         check_assist(
884             change_return_type_to_result,
885             r#"fn foo(the_field: u32) -> u3<|>2 {
886                 if the_field < 5 {
887                     let mut i = 0;
888
889                     match i {
890                         5 => return 99,
891                         _ => return 0,
892                     }
893                 }
894
895                 the_field
896             }"#,
897             r#"fn foo(the_field: u32) -> Result<u32, <|>> {
898                 if the_field < 5 {
899                     let mut i = 0;
900
901                     match i {
902                         5 => return Ok(99),
903                         _ => return Ok(0),
904                     }
905                 }
906
907                 Ok(the_field)
908             }"#,
909         );
910
911         check_assist(
912             change_return_type_to_result,
913             r#"fn foo(the_field: u32) -> u32<|> {
914                 if the_field < 5 {
915                     let mut i = 0;
916
917                     if i == 5 {
918                         return 99
919                     } else {
920                         return 0
921                     }
922                 }
923
924                 the_field
925             }"#,
926             r#"fn foo(the_field: u32) -> Result<u32, <|>> {
927                 if the_field < 5 {
928                     let mut i = 0;
929
930                     if i == 5 {
931                         return Ok(99)
932                     } else {
933                         return Ok(0)
934                     }
935                 }
936
937                 Ok(the_field)
938             }"#,
939         );
940
941         check_assist(
942             change_return_type_to_result,
943             r#"fn foo(the_field: u32) -> <|>u32 {
944                 if the_field < 5 {
945                     let mut i = 0;
946
947                     if i == 5 {
948                         return 99;
949                     } else {
950                         return 0;
951                     }
952                 }
953
954                 the_field
955             }"#,
956             r#"fn foo(the_field: u32) -> Result<u32, <|>> {
957                 if the_field < 5 {
958                     let mut i = 0;
959
960                     if i == 5 {
961                         return Ok(99);
962                     } else {
963                         return Ok(0);
964                     }
965                 }
966
967                 Ok(the_field)
968             }"#,
969         );
970     }
971 }