diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index 25a66029cb9a..523e0f7f7d70 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs @@ -8,6 +8,7 @@ search::{FileReference, ReferenceAccess, SearchScope}, RootDatabase, }; +use itertools::Itertools; use rustc_hash::FxHasher; use stdx::format_to; use syntax::{ @@ -389,8 +390,23 @@ fn from_expr(expr: ast::Expr) -> Option { } } - fn from_range(parent: ast::BlockExpr, text_range: TextRange) -> FunctionBody { - Self::Span { parent, text_range } + fn from_range(parent: ast::BlockExpr, selected: TextRange) -> FunctionBody { + let mut text_range = parent + .statements() + .map(|stmt| stmt.syntax().text_range()) + .filter(|&stmt| selected.intersect(stmt).filter(|it| !it.is_empty()).is_some()) + .fold1(|acc, stmt| acc.cover(stmt)); + if let Some(tail_range) = parent + .tail_expr() + .map(|it| it.syntax().text_range()) + .filter(|&it| selected.intersect(it).is_some()) + { + text_range = Some(match text_range { + Some(text_range) => text_range.cover(tail_range), + None => tail_range, + }); + } + Self::Span { parent, text_range: text_range.unwrap_or(selected) } } fn indent_level(&self) -> IndentLevel { @@ -546,17 +562,7 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option { @@ -599,6 +604,8 @@ fn analyze_body( stdx::never!("Local::is_self returned true, but source is IdentPat"); } } + } else { + res.insert(local_ref); } } } @@ -615,7 +622,6 @@ fn extracted_function_params( locals: impl Iterator, ) -> Vec { locals - .filter(|local| !local.is_self(ctx.db())) .map(|local| (local, local.source(ctx.db()))) .filter(|(_, src)| is_defined_outside_of_body(ctx, body, src)) .filter_map(|(local, src)| { @@ -3230,8 +3236,7 @@ fn return_from_nested_loop() { r#" fn foo() { loop { - let n = 1; - $0 + let n = 1;$0 let k = 1; loop { return; @@ -3435,8 +3440,7 @@ fn break_with_value_and_return() { r#" fn foo() -> i64 { loop { - let n = 1; - $0 + let n = 1;$0 let k = 1; if k == 42 { break 3; @@ -3830,6 +3834,33 @@ fn main() { fn $0fun_name() -> i32 { 100 } +"#, + ); + } + + #[test] + fn extract_does_not_tear_comments_apart() { + check_assist( + extract_function, + r#" +fn foo() { + /*$0*/ + foo(); + foo(); + /*$0*/ +} +"#, + r#" +fn foo() { + /**/ + fun_name(); + /**/ +} + +fn $0fun_name() { + foo(); + foo(); +} "#, ); }