@@ -16,7 +16,7 @@ use syntax::{
16
16
AstNode ,
17
17
} ,
18
18
ted,
19
- SyntaxKind :: { self , BLOCK_EXPR , BREAK_EXPR , COMMENT , PATH_EXPR , RETURN_EXPR } ,
19
+ SyntaxKind :: { self , COMMENT } ,
20
20
SyntaxNode , SyntaxToken , TextRange , TextSize , TokenAtOffset , WalkEvent , T ,
21
21
} ;
22
22
@@ -466,22 +466,17 @@ enum FunctionBody {
466
466
}
467
467
468
468
impl 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) ) ,
479
475
}
480
476
}
481
477
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 }
485
480
}
486
481
487
482
fn indent_level ( & self ) -> IndentLevel {
@@ -592,44 +587,39 @@ struct OutlivedLocal {
592
587
/// ```
593
588
///
594
589
fn 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
+ } ;
602
598
}
603
599
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 ( ) ) ;
616
604
}
617
605
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 ( ) ) ;
628
618
}
619
+ return Some ( FunctionBody :: from_range ( block, statements_range) ) ;
629
620
}
630
621
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)
633
623
}
634
624
635
625
/// list local variables that are referenced in `body`
@@ -3743,6 +3733,16 @@ async fn $0fun_name() {
3743
3733
async fn some_function() {
3744
3734
3745
3735
}
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
3746
3746
"# ,
3747
3747
) ;
3748
3748
}
0 commit comments