]> 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 06195624ed0f7d79cd57236617d3487f1f2e29d1..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;
 // }
 // ```
@@ -69,16 +71,12 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
         return None;
     }
 
-    println!("initial node: {:?}", node);
-
     let node = match node {
         syntax::NodeOrToken::Node(n) => n,
         syntax::NodeOrToken::Token(t) => t.parent()?,
     };
 
-    println!("next node: {:?}", node);
     let body = extraction_target(&node, range)?;
-    println!("body: {:?}", body);
     let container_info = body.analyze_container(&ctx.sema)?;
 
     let (locals_used, self_param) = body.analyze(&ctx.sema);
@@ -187,8 +185,6 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
         };
     }
 
-    println!("node: {:?}", node);
-
     // Covering element returned the parent block of one or multiple statements that have been selected
     if let Some(stmt_list) = ast::StmtList::cast(node.clone()) {
         if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) {
@@ -198,8 +194,6 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
         }
 
         // Extract the full statements.
-        println!("stmt_list: {:?}", stmt_list);
-        println!("selection_range: {:?}", selection_range);
         return Some(FunctionBody::from_range(stmt_list, selection_range));
     }
 
@@ -486,16 +480,13 @@ fn from_expr(expr: ast::Expr) -> Option<Self> {
 
     fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody {
         let full_body = parent.syntax().children_with_tokens();
-        for st in parent.syntax().children_with_tokens() {
-            println!("Statement: {:?}", &st);
-        }
 
         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));
 
-        println!("from_range text_range first: {:?}", text_range);
         if let Some(tail_range) = parent
             .tail_expr()
             .map(|it| it.syntax().text_range())
@@ -505,8 +496,6 @@ fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody {
                 Some(text_range) => text_range.cover(tail_range),
                 None => tail_range,
             });
-
-            println!("from_range text_range second: {:?}", text_range);
         }
         Self::Span { parent, text_range: text_range.unwrap_or(selected) }
     }
@@ -1230,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";
@@ -1438,7 +1425,6 @@ fn make_body(
         FlowHandler::from_ret_ty(fun, &ret_ty)
     };
 
-    println!("making body: {:?}", fun.body);
     let block = match &fun.body {
         FunctionBody::Expr(expr) => {
             let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
@@ -1462,28 +1448,19 @@ fn make_body(
                 .syntax()
                 .children_with_tokens()
                 .filter(|it| text_range.contains_range(it.text_range()))
-                .map(|it| match it {
-                    syntax::NodeOrToken::Node(n) => {
-                        println!("Found node: {:?}", n);
-                        let node_rewritten = rewrite_body_segment(ctx, &fun.params, &handler, &n);
-
-                        syntax::NodeOrToken::Node(node_rewritten)
-                    }
-                    syntax::NodeOrToken::Token(t) => {
-                        println!("Found token: {:?}", t);
-                        syntax::NodeOrToken::Token(t)
-                    }
+                .map(|it| match &it {
+                    syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
+                        rewrite_body_segment(ctx, &fun.params, &handler, &n),
+                    ),
+                    _ => 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 {
@@ -1504,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()) {
@@ -1513,20 +1490,14 @@ 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,
                 })
                 .collect::<Vec<SyntaxElement>>();
             let tail_expr = tail_expr.map(|expr| expr.dedent(old_indent).indent(body_indent));
 
-            for element in &elements {
-                println!("element: {:?}", element);
-            }
-
-            make::block_expr_full(elements, tail_expr)
-
-            // make::block_expr(parent.statements().into_iter(), tail_expr)
+            make::hacky_block_expr_with_comments(elements, tail_expr)
         }
     };
 
@@ -4151,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(
@@ -4475,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
@@ -4485,7 +4476,6 @@ fn func() {
             r#"
 fn func() {
     let i = 0;
-    
     fun_name();
 }
 
@@ -4552,6 +4542,7 @@ fn $0fun_name() {
         );
     }
 
+    // FIXME: we do want to preserve whitespace
     #[test]
     fn extract_function_does_not_preserve_whitespace() {
         check_assist(