@@ -288,14 +288,14 @@ fn handle_control_flow_keywords(
288
288
token : & SyntaxToken ,
289
289
) -> Option < Vec < NavigationTarget > > {
290
290
match token. kind ( ) {
291
- // For `fn` / `loop` / `while` / `for` / `async`, return the keyword it self,
291
+ // For `fn` / `loop` / `while` / `for` / `async` / `match` , return the keyword it self,
292
292
// so that VSCode will find the references when using `ctrl + click`
293
293
T ! [ fn ] | T ! [ async ] | T ! [ try] | T ! [ return ] => nav_for_exit_points ( sema, token) ,
294
294
T ! [ loop ] | T ! [ while ] | T ! [ break ] | T ! [ continue ] => nav_for_break_points ( sema, token) ,
295
295
T ! [ for ] if token. parent ( ) . and_then ( ast:: ForExpr :: cast) . is_some ( ) => {
296
296
nav_for_break_points ( sema, token)
297
297
}
298
- T ! [ match ] | T ! [ =>] | T ! [ if ] => nav_for_branches ( sema, token) ,
298
+ T ! [ match ] | T ! [ =>] | T ! [ if ] => nav_for_branch_exit_points ( sema, token) ,
299
299
_ => None ,
300
300
}
301
301
}
@@ -405,21 +405,65 @@ fn nav_for_exit_points(
405
405
Some ( navs)
406
406
}
407
407
408
- fn nav_for_branches (
408
+ pub ( crate ) fn find_branch_root (
409
+ sema : & Semantics < ' _ , RootDatabase > ,
410
+ token : & SyntaxToken ,
411
+ ) -> Vec < SyntaxNode > {
412
+ fn find_root (
413
+ sema : & Semantics < ' _ , RootDatabase > ,
414
+ token : & SyntaxToken ,
415
+ pred : impl Fn ( SyntaxNode ) -> Option < SyntaxNode > ,
416
+ ) -> Vec < SyntaxNode > {
417
+ let mut result = Vec :: new ( ) ;
418
+ for token in sema. descend_into_macros ( token. clone ( ) ) {
419
+ for node in sema. token_ancestors_with_macros ( token) {
420
+ if ast:: MacroCall :: can_cast ( node. kind ( ) ) {
421
+ break ;
422
+ }
423
+
424
+ if let Some ( node) = pred ( node) {
425
+ result. push ( node) ;
426
+ break ;
427
+ }
428
+ }
429
+ }
430
+ result
431
+ }
432
+
433
+ match token. kind ( ) {
434
+ T ! [ match ] => {
435
+ find_root ( sema, token, |node| Some ( ast:: MatchExpr :: cast ( node) ?. syntax ( ) . clone ( ) ) )
436
+ }
437
+ T ! [ =>] => find_root ( sema, token, |node| Some ( ast:: MatchArm :: cast ( node) ?. syntax ( ) . clone ( ) ) ) ,
438
+ T ! [ if ] => find_root ( sema, token, |node| {
439
+ let if_expr = ast:: IfExpr :: cast ( node) ?;
440
+
441
+ iter:: successors ( Some ( if_expr. clone ( ) ) , |if_expr| {
442
+ let parent_if = if_expr. syntax ( ) . parent ( ) . and_then ( ast:: IfExpr :: cast) ?;
443
+ if let ast:: ElseBranch :: IfExpr ( nested_if) = parent_if. else_branch ( ) ? {
444
+ ( nested_if. syntax ( ) == if_expr. syntax ( ) ) . then_some ( parent_if)
445
+ } else {
446
+ None
447
+ }
448
+ } )
449
+ . last ( )
450
+ . map ( |if_expr| if_expr. syntax ( ) . clone ( ) )
451
+ } ) ,
452
+ _ => vec ! [ ] ,
453
+ }
454
+ }
455
+
456
+ fn nav_for_branch_exit_points (
409
457
sema : & Semantics < ' _ , RootDatabase > ,
410
458
token : & SyntaxToken ,
411
459
) -> Option < Vec < NavigationTarget > > {
412
460
let db = sema. db ;
413
461
414
462
let navs = match token. kind ( ) {
415
- T ! [ match ] => sema
416
- . descend_into_macros ( token. clone ( ) )
463
+ T ! [ match ] => find_branch_root ( sema, token)
417
464
. into_iter ( )
418
- . filter_map ( |token| {
419
- let match_expr = sema
420
- . token_ancestors_with_macros ( token)
421
- . take_while ( |node| !ast:: MacroCall :: can_cast ( node. kind ( ) ) )
422
- . find_map ( ast:: MatchExpr :: cast) ?;
465
+ . filter_map ( |node| {
466
+ let match_expr = ast:: MatchExpr :: cast ( node) ?;
423
467
let file_id = sema. hir_file_for ( match_expr. syntax ( ) ) ;
424
468
let focus_range = match_expr. match_token ( ) ?. text_range ( ) ;
425
469
let match_expr_in_file = InFile :: new ( file_id, match_expr. into ( ) ) ;
@@ -428,14 +472,10 @@ fn nav_for_branches(
428
472
. flatten ( )
429
473
. collect_vec ( ) ,
430
474
431
- T ! [ =>] => sema
432
- . descend_into_macros ( token. clone ( ) )
475
+ T ! [ =>] => find_branch_root ( sema, token)
433
476
. into_iter ( )
434
- . filter_map ( |token| {
435
- let match_arm = sema
436
- . token_ancestors_with_macros ( token)
437
- . take_while ( |node| !ast:: MacroCall :: can_cast ( node. kind ( ) ) )
438
- . find_map ( ast:: MatchArm :: cast) ?;
477
+ . filter_map ( |node| {
478
+ let match_arm = ast:: MatchArm :: cast ( node) ?;
439
479
let match_expr = sema
440
480
. ancestors_with_macros ( match_arm. syntax ( ) . clone ( ) )
441
481
. find_map ( ast:: MatchExpr :: cast) ?;
@@ -447,14 +487,10 @@ fn nav_for_branches(
447
487
. flatten ( )
448
488
. collect_vec ( ) ,
449
489
450
- T ! [ if ] => sema
451
- . descend_into_macros ( token. clone ( ) )
490
+ T ! [ if ] => find_branch_root ( sema, token)
452
491
. into_iter ( )
453
- . filter_map ( |token| {
454
- let if_expr = sema
455
- . token_ancestors_with_macros ( token)
456
- . take_while ( |node| !ast:: MacroCall :: can_cast ( node. kind ( ) ) )
457
- . find_map ( ast:: IfExpr :: cast) ?;
492
+ . filter_map ( |node| {
493
+ let if_expr = ast:: IfExpr :: cast ( node) ?;
458
494
let file_id = sema. hir_file_for ( if_expr. syntax ( ) ) ;
459
495
let focus_range = if_expr. if_token ( ) ?. text_range ( ) ;
460
496
let if_expr_in_file = InFile :: new ( file_id, if_expr. into ( ) ) ;
@@ -3497,9 +3533,9 @@ fn main() {
3497
3533
r#"
3498
3534
fn main() {
3499
3535
if true {
3536
+ // ^^
3500
3537
()
3501
3538
} else if$0 false {
3502
- // ^^
3503
3539
()
3504
3540
} else {
3505
3541
()
0 commit comments