@@ -291,14 +291,14 @@ fn handle_control_flow_keywords(
291291 token : & SyntaxToken ,
292292) -> Option < Vec < NavigationTarget > > {
293293 match token. kind ( ) {
294- // For `fn` / `loop` / `while` / `for` / `async`, return the keyword it self,
294+ // For `fn` / `loop` / `while` / `for` / `async` / `match` , return the keyword it self,
295295 // so that VSCode will find the references when using `ctrl + click`
296296 T ! [ fn ] | T ! [ async ] | T ! [ try] | T ! [ return ] => nav_for_exit_points ( sema, token) ,
297297 T ! [ loop ] | T ! [ while ] | T ! [ break ] | T ! [ continue ] => nav_for_break_points ( sema, token) ,
298298 T ! [ for ] if token. parent ( ) . and_then ( ast:: ForExpr :: cast) . is_some ( ) => {
299299 nav_for_break_points ( sema, token)
300300 }
301- T ! [ match ] | T ! [ =>] | T ! [ if ] => nav_for_branches ( sema, token) ,
301+ T ! [ match ] | T ! [ =>] | T ! [ if ] => nav_for_branch_exit_points ( sema, token) ,
302302 _ => None ,
303303 }
304304}
@@ -408,37 +408,77 @@ fn nav_for_exit_points(
408408 Some ( navs)
409409}
410410
411- fn nav_for_branches (
411+ pub ( crate ) fn find_branch_root (
412+ sema : & Semantics < ' _ , RootDatabase > ,
413+ token : & SyntaxToken ,
414+ ) -> Vec < SyntaxNode > {
415+ fn find_root (
416+ sema : & Semantics < ' _ , RootDatabase > ,
417+ token : & SyntaxToken ,
418+ pred : impl Fn ( SyntaxNode ) -> Option < SyntaxNode > ,
419+ ) -> Vec < SyntaxNode > {
420+ let mut result = Vec :: new ( ) ;
421+ for token in sema. descend_into_macros ( token. clone ( ) ) {
422+ for node in sema. token_ancestors_with_macros ( token) {
423+ if ast:: MacroCall :: can_cast ( node. kind ( ) ) {
424+ break ;
425+ }
426+
427+ if let Some ( node) = pred ( node) {
428+ result. push ( node) ;
429+ break ;
430+ }
431+ }
432+ }
433+ result
434+ }
435+
436+ match token. kind ( ) {
437+ T ! [ match ] => {
438+ find_root ( sema, token, |node| Some ( ast:: MatchExpr :: cast ( node) ?. syntax ( ) . clone ( ) ) )
439+ }
440+ T ! [ =>] => find_root ( sema, token, |node| Some ( ast:: MatchArm :: cast ( node) ?. syntax ( ) . clone ( ) ) ) ,
441+ T ! [ if ] => find_root ( sema, token, |node| {
442+ let if_expr = ast:: IfExpr :: cast ( node) ?;
443+
444+ iter:: successors ( Some ( if_expr. clone ( ) ) , |if_expr| {
445+ let parent_if = if_expr. syntax ( ) . parent ( ) . and_then ( ast:: IfExpr :: cast) ?;
446+ if let ast:: ElseBranch :: IfExpr ( nested_if) = parent_if. else_branch ( ) ? {
447+ ( nested_if. syntax ( ) == if_expr. syntax ( ) ) . then_some ( parent_if)
448+ } else {
449+ None
450+ }
451+ } )
452+ . last ( )
453+ . map ( |if_expr| if_expr. syntax ( ) . clone ( ) )
454+ } ) ,
455+ _ => vec ! [ ] ,
456+ }
457+ }
458+
459+ fn nav_for_branch_exit_points (
412460 sema : & Semantics < ' _ , RootDatabase > ,
413461 token : & SyntaxToken ,
414462) -> Option < Vec < NavigationTarget > > {
415463 let db = sema. db ;
416464
417465 let navs = match token. kind ( ) {
418- T ! [ match ] => sema
419- . descend_into_macros ( token. clone ( ) )
466+ T ! [ match ] => find_branch_root ( sema, token)
420467 . into_iter ( )
421- . filter_map ( |token| {
422- let match_expr = sema
423- . token_ancestors_with_macros ( token)
424- . take_while ( |node| !ast:: MacroCall :: can_cast ( node. kind ( ) ) )
425- . find_map ( ast:: MatchExpr :: cast) ?;
426- let file_id = sema. hir_file_for ( match_expr. syntax ( ) ) ;
468+ . filter_map ( |node| {
469+ let file_id = sema. hir_file_for ( & node) ;
470+ let match_expr = ast:: MatchExpr :: cast ( node) ?;
427471 let focus_range = match_expr. match_token ( ) ?. text_range ( ) ;
428472 let match_expr_in_file = InFile :: new ( file_id, match_expr. into ( ) ) ;
429473 Some ( expr_to_nav ( db, match_expr_in_file, Some ( focus_range) ) )
430474 } )
431475 . flatten ( )
432476 . collect_vec ( ) ,
433477
434- T ! [ =>] => sema
435- . descend_into_macros ( token. clone ( ) )
478+ T ! [ =>] => find_branch_root ( sema, token)
436479 . into_iter ( )
437- . filter_map ( |token| {
438- let match_arm = sema
439- . token_ancestors_with_macros ( token)
440- . take_while ( |node| !ast:: MacroCall :: can_cast ( node. kind ( ) ) )
441- . find_map ( ast:: MatchArm :: cast) ?;
480+ . filter_map ( |node| {
481+ let match_arm = ast:: MatchArm :: cast ( node) ?;
442482 let match_expr = sema
443483 . ancestors_with_macros ( match_arm. syntax ( ) . clone ( ) )
444484 . find_map ( ast:: MatchExpr :: cast) ?;
@@ -450,15 +490,11 @@ fn nav_for_branches(
450490 . flatten ( )
451491 . collect_vec ( ) ,
452492
453- T ! [ if ] => sema
454- . descend_into_macros ( token. clone ( ) )
493+ T ! [ if ] => find_branch_root ( sema, token)
455494 . into_iter ( )
456- . filter_map ( |token| {
457- let if_expr = sema
458- . token_ancestors_with_macros ( token)
459- . take_while ( |node| !ast:: MacroCall :: can_cast ( node. kind ( ) ) )
460- . find_map ( ast:: IfExpr :: cast) ?;
461- let file_id = sema. hir_file_for ( if_expr. syntax ( ) ) ;
495+ . filter_map ( |node| {
496+ let file_id = sema. hir_file_for ( & node) ;
497+ let if_expr = ast:: IfExpr :: cast ( node) ?;
462498 let focus_range = if_expr. if_token ( ) ?. text_range ( ) ;
463499 let if_expr_in_file = InFile :: new ( file_id, if_expr. into ( ) ) ;
464500 Some ( expr_to_nav ( db, if_expr_in_file, Some ( focus_range) ) )
@@ -3785,9 +3821,9 @@ fn main() {
37853821 r#"
37863822fn main() {
37873823 if true {
3824+ // ^^
37883825 ()
37893826 } else if$0 false {
3790- // ^^
37913827 ()
37923828 } else {
37933829 ()
0 commit comments