]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_assists/src/handlers/extract_function.rs
Merge #11481
[rust.git] / crates / ide_assists / src / handlers / extract_function.rs
index 3ceffbba97f68e881e7fbaa77048cecb982d9419..21cfc76ac9bf6036d100c489218ca0deb6c171ca 100644 (file)
 
 // Assist: extract_function
 //
-// Extracts selected statements into new function.
+// Extracts selected statements and comments into new function.
 //
 // ```
 // fn main() {
 //     let n = 1;
 //     $0let m = n + 2;
+//     // calculate
 //     let k = m + n;$0
 //     let g = 3;
 // }
@@ -54,6 +55,7 @@
 //
 // fn $0fun_name(n: i32) {
 //     let m = n + 2;
+//     // calculate
 //     let k = m + n;
 // }
 // ```
@@ -480,8 +482,9 @@ fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody {
         let full_body = parent.syntax().children_with_tokens();
 
         let mut text_range = full_body
-            .map(|stmt| stmt.text_range())
-            .filter(|&stmt| selected.intersect(stmt).filter(|it| !it.is_empty()).is_some())
+            .filter(|it| ast::Stmt::can_cast(it.kind()) || it.kind() == COMMENT)
+            .map(|element| element.text_range())
+            .filter(|&range| selected.intersect(range).filter(|it| !it.is_empty()).is_some())
             .reduce(|acc, stmt| acc.cover(stmt));
 
         if let Some(tail_range) = parent
@@ -1216,28 +1219,26 @@ fn make_call_expr(&self, call_expr: ast::Expr) -> ast::Expr {
                 let stmt = make::expr_stmt(action);
                 let block = make::block_expr(iter::once(stmt.into()), None);
                 let controlflow_break_path = make::path_from_text("ControlFlow::Break");
-                let condition = make::condition(
+                let condition = make::expr_let(
+                    make::tuple_struct_pat(
+                        controlflow_break_path,
+                        iter::once(make::wildcard_pat().into()),
+                    )
+                    .into(),
                     call_expr,
-                    Some(
-                        make::tuple_struct_pat(
-                            controlflow_break_path,
-                            iter::once(make::wildcard_pat().into()),
-                        )
-                        .into(),
-                    ),
                 );
-                make::expr_if(condition, block, None)
+                make::expr_if(condition.into(), block, None)
             }
             FlowHandler::IfOption { action } => {
                 let path = make::ext::ident_path("Some");
                 let value_pat = make::ext::simple_ident_pat(make::name("value"));
                 let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
-                let cond = make::condition(call_expr, Some(pattern.into()));
+                let cond = make::expr_let(pattern.into(), call_expr);
                 let value = make::expr_path(make::ext::ident_path("value"));
                 let action_expr = action.make_result_handler(Some(value));
                 let action_stmt = make::expr_stmt(action_expr);
                 let then = make::block_expr(iter::once(action_stmt.into()), None);
-                make::expr_if(cond, then, None)
+                make::expr_if(cond.into(), then, None)
             }
             FlowHandler::MatchOption { none } => {
                 let some_name = "value";
@@ -1451,18 +1452,15 @@ fn make_body(
                     syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
                         rewrite_body_segment(ctx, &fun.params, &handler, &n),
                     ),
-                    syntax::NodeOrToken::Token(_) => it,
+                    _ => it,
                 })
                 .collect();
 
             let mut tail_expr = match &elements.last() {
-                Some(element) => match element {
-                    syntax::NodeOrToken::Node(node) if ast::Expr::can_cast(node.kind()) => {
-                        ast::Expr::cast(node.clone())
-                    }
-                    _ => None,
-                },
-                None => None,
+                Some(syntax::NodeOrToken::Node(node)) if ast::Expr::can_cast(node.kind()) => {
+                    ast::Expr::cast(node.clone())
+                }
+                _ => None,
             };
 
             match tail_expr {
@@ -1483,7 +1481,7 @@ fn make_body(
             };
 
             let body_indent = IndentLevel(1);
-            let elements: Vec<SyntaxElement> = elements
+            let elements = elements
                 .into_iter()
                 .map(|node_or_token| match &node_or_token {
                     syntax::NodeOrToken::Node(node) => match ast::Stmt::cast(node.clone()) {
@@ -1492,7 +1490,7 @@ fn make_body(
                             let ast_node = indented.syntax().clone_subtree();
                             syntax::NodeOrToken::Node(ast_node)
                         }
-                        None => node_or_token,
+                        _ => node_or_token,
                     },
                     _ => node_or_token,
                 })
@@ -4124,6 +4122,27 @@ fn $0fun_name() {
         );
     }
 
+    #[test]
+    fn extract_does_not_tear_body_apart() {
+        check_assist(
+            extract_function,
+            r#"
+fn foo() {
+    $0foo();
+}$0
+"#,
+            r#"
+fn foo() {
+    fun_name();
+}
+
+fn $0fun_name() {
+    foo();
+}
+"#,
+        );
+    }
+
     #[test]
     fn extract_does_not_wrap_res_in_res() {
         check_assist(
@@ -4448,8 +4467,7 @@ fn extract_function_copies_comment_in_between() {
             extract_function,
             r#"
 fn func() {
-    let i = 0;
-    $0
+    let i = 0;$0
     let a = 0;
     // comment here!
     let x = 0;$0
@@ -4458,7 +4476,6 @@ fn func() {
             r#"
 fn func() {
     let i = 0;
-    
     fun_name();
 }
 
@@ -4525,6 +4542,7 @@ fn $0fun_name() {
         );
     }
 
+    // FIXME: we do want to preserve whitespace
     #[test]
     fn extract_function_does_not_preserve_whitespace() {
         check_assist(