@@ -16,7 +16,7 @@ use syntax::{
1616 AstNode ,
1717 } ,
1818 ted,
19- SyntaxKind :: { self , BLOCK_EXPR , BREAK_EXPR , COMMENT , PATH_EXPR , RETURN_EXPR } ,
19+ SyntaxKind :: { self , COMMENT } ,
2020 SyntaxNode , SyntaxToken , TextRange , TextSize , TokenAtOffset , WalkEvent , T ,
2121} ;
2222
@@ -466,22 +466,17 @@ enum FunctionBody {
466466}
467467
468468impl FunctionBody {
469- fn from_whole_node ( node : SyntaxNode ) -> Option < Self > {
470- match node. kind ( ) {
471- PATH_EXPR => None ,
472- BREAK_EXPR => ast:: BreakExpr :: cast ( node) . and_then ( |e| e. expr ( ) ) . map ( Self :: Expr ) ,
473- RETURN_EXPR => ast:: ReturnExpr :: cast ( node) . and_then ( |e| e. expr ( ) ) . map ( Self :: Expr ) ,
474- BLOCK_EXPR => ast:: BlockExpr :: cast ( node)
475- . filter ( |it| it. is_standalone ( ) )
476- . map ( Into :: into)
477- . map ( Self :: Expr ) ,
478- _ => ast:: Expr :: cast ( node) . map ( Self :: Expr ) ,
469+ fn from_expr ( expr : ast:: Expr ) -> Option < Self > {
470+ match expr {
471+ ast:: Expr :: BreakExpr ( it) => it. expr ( ) . map ( Self :: Expr ) ,
472+ ast:: Expr :: ReturnExpr ( it) => it. expr ( ) . map ( Self :: Expr ) ,
473+ ast:: Expr :: BlockExpr ( it) if !it. is_standalone ( ) => None ,
474+ expr => Some ( Self :: Expr ( expr) ) ,
479475 }
480476 }
481477
482- fn from_range ( node : SyntaxNode , text_range : TextRange ) -> Option < FunctionBody > {
483- let block = ast:: BlockExpr :: cast ( node) ?;
484- Some ( Self :: Span { parent : block, text_range } )
478+ fn from_range ( parent : ast:: BlockExpr , text_range : TextRange ) -> FunctionBody {
479+ Self :: Span { parent, text_range }
485480 }
486481
487482 fn indent_level ( & self ) -> IndentLevel {
@@ -592,44 +587,39 @@ struct OutlivedLocal {
592587/// ```
593588///
594589fn extraction_target ( node : & SyntaxNode , selection_range : TextRange ) -> Option < FunctionBody > {
595- // we have selected exactly the expr node
596- // wrap it before anything else
597- if node. text_range ( ) == selection_range {
598- let body = FunctionBody :: from_whole_node ( node. clone ( ) ) ;
599- if body. is_some ( ) {
600- return body;
601- }
590+ if let Some ( stmt) = ast:: Stmt :: cast ( node. clone ( ) ) {
591+ return match stmt {
592+ ast:: Stmt :: Item ( _) => None ,
593+ ast:: Stmt :: ExprStmt ( _) | ast:: Stmt :: LetStmt ( _) => Some ( FunctionBody :: from_range (
594+ node. parent ( ) . and_then ( ast:: BlockExpr :: cast) ?,
595+ node. text_range ( ) ,
596+ ) ) ,
597+ } ;
602598 }
603599
604- // we have selected a few statements in a block
605- // so covering_element returns the whole block
606- if node. kind ( ) == BLOCK_EXPR {
607- // Extract the full statements.
608- let statements_range = node
609- . children ( )
610- . filter ( |c| selection_range. intersect ( c. text_range ( ) ) . is_some ( ) )
611- . fold ( selection_range, |acc, c| acc. cover ( c. text_range ( ) ) ) ;
612- let body = FunctionBody :: from_range ( node. clone ( ) , statements_range) ;
613- if body. is_some ( ) {
614- return body;
615- }
600+ let expr = ast:: Expr :: cast ( node. clone ( ) ) ?;
601+ // A node got selected fully
602+ if node. text_range ( ) == selection_range {
603+ return FunctionBody :: from_expr ( expr. clone ( ) ) ;
616604 }
617605
618- // we have selected single statement
619- // `from_whole_node` failed because (let) statement is not and expression
620- // so we try to expand covering_element to parent and repeat the previous
621- if let Some ( parent) = node. parent ( ) {
622- if parent. kind ( ) == BLOCK_EXPR {
623- // Extract the full statement.
624- let body = FunctionBody :: from_range ( parent, node. text_range ( ) ) ;
625- if body. is_some ( ) {
626- return body;
627- }
606+ // Covering element returned the parent block of one or multiple statements that have been selected
607+ if let ast:: Expr :: BlockExpr ( block) = expr {
608+ // Extract the full statements.
609+ let mut statements_range = block
610+ . statements ( )
611+ . filter ( |stmt| selection_range. intersect ( stmt. syntax ( ) . text_range ( ) ) . is_some ( ) )
612+ . fold ( selection_range, |acc, stmt| acc. cover ( stmt. syntax ( ) . text_range ( ) ) ) ;
613+ if let Some ( e) = block
614+ . tail_expr ( )
615+ . filter ( |it| selection_range. intersect ( it. syntax ( ) . text_range ( ) ) . is_some ( ) )
616+ {
617+ statements_range = statements_range. cover ( e. syntax ( ) . text_range ( ) ) ;
628618 }
619+ return Some ( FunctionBody :: from_range ( block, statements_range) ) ;
629620 }
630621
631- // select the closest containing expr (both ifs are used)
632- std:: iter:: once ( node. clone ( ) ) . chain ( node. ancestors ( ) ) . find_map ( FunctionBody :: from_whole_node)
622+ node. ancestors ( ) . find_map ( ast:: Expr :: cast) . and_then ( FunctionBody :: from_expr)
633623}
634624
635625/// list local variables that are referenced in `body`
@@ -3743,6 +3733,16 @@ async fn $0fun_name() {
37433733async fn some_function() {
37443734
37453735}
3736+ "# ,
3737+ ) ;
3738+ }
3739+
3740+ #[ test]
3741+ fn extract_does_not_extract_standalone_blocks ( ) {
3742+ check_assist_not_applicable (
3743+ extract_function,
3744+ r#"
3745+ fn main() $0{}$0
37463746"# ,
37473747 ) ;
37483748 }
0 commit comments