@@ -291,13 +291,14 @@ fn handle_control_flow_keywords(
291
291
token : & SyntaxToken ,
292
292
) -> Option < Vec < NavigationTarget > > {
293
293
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,
295
295
// so that VSCode will find the references when using `ctrl + click`
296
296
T ! [ fn ] | T ! [ async ] | T ! [ try] | T ! [ return ] => nav_for_exit_points ( sema, token) ,
297
297
T ! [ loop ] | T ! [ while ] | T ! [ break ] | T ! [ continue ] => nav_for_break_points ( sema, token) ,
298
298
T ! [ for ] if token. parent ( ) . and_then ( ast:: ForExpr :: cast) . is_some ( ) => {
299
299
nav_for_break_points ( sema, token)
300
300
}
301
+ T ! [ match ] | T ! [ =>] | T ! [ if ] => nav_for_branch_exit_points ( sema, token) ,
301
302
_ => None ,
302
303
}
303
304
}
@@ -407,6 +408,91 @@ fn nav_for_exit_points(
407
408
Some ( navs)
408
409
}
409
410
411
+ pub ( crate ) fn find_branch_root (
412
+ sema : & Semantics < ' _ , RootDatabase > ,
413
+ token : & SyntaxToken ,
414
+ ) -> Vec < SyntaxNode > {
415
+ let find_nodes = |node_filter : fn ( SyntaxNode ) -> Option < SyntaxNode > | {
416
+ sema. descend_into_macros ( token. clone ( ) )
417
+ . into_iter ( )
418
+ . filter_map ( |token| node_filter ( token. parent ( ) ?) )
419
+ . collect_vec ( )
420
+ } ;
421
+
422
+ match token. kind ( ) {
423
+ T ! [ match ] => find_nodes ( |node| Some ( ast:: MatchExpr :: cast ( node) ?. syntax ( ) . clone ( ) ) ) ,
424
+ T ! [ =>] => find_nodes ( |node| Some ( ast:: MatchArm :: cast ( node) ?. syntax ( ) . clone ( ) ) ) ,
425
+ T ! [ if ] => find_nodes ( |node| {
426
+ let if_expr = ast:: IfExpr :: cast ( node) ?;
427
+
428
+ let root_if = iter:: successors ( Some ( if_expr. clone ( ) ) , |if_expr| {
429
+ let parent_if = if_expr. syntax ( ) . parent ( ) . and_then ( ast:: IfExpr :: cast) ?;
430
+ let ast:: ElseBranch :: IfExpr ( else_branch) = parent_if. else_branch ( ) ? else {
431
+ return None ;
432
+ } ;
433
+
434
+ ( else_branch. syntax ( ) == if_expr. syntax ( ) ) . then_some ( parent_if)
435
+ } )
436
+ . last ( ) ?;
437
+
438
+ Some ( root_if. syntax ( ) . clone ( ) )
439
+ } ) ,
440
+ _ => vec ! [ ] ,
441
+ }
442
+ }
443
+
444
+ fn nav_for_branch_exit_points (
445
+ sema : & Semantics < ' _ , RootDatabase > ,
446
+ token : & SyntaxToken ,
447
+ ) -> Option < Vec < NavigationTarget > > {
448
+ let db = sema. db ;
449
+
450
+ let navs = match token. kind ( ) {
451
+ T ! [ match ] => find_branch_root ( sema, token)
452
+ . into_iter ( )
453
+ . filter_map ( |node| {
454
+ let file_id = sema. hir_file_for ( & node) ;
455
+ let match_expr = ast:: MatchExpr :: cast ( node) ?;
456
+ let focus_range = match_expr. match_token ( ) ?. text_range ( ) ;
457
+ let match_expr_in_file = InFile :: new ( file_id, match_expr. into ( ) ) ;
458
+ Some ( expr_to_nav ( db, match_expr_in_file, Some ( focus_range) ) )
459
+ } )
460
+ . flatten ( )
461
+ . collect_vec ( ) ,
462
+
463
+ T ! [ =>] => find_branch_root ( sema, token)
464
+ . into_iter ( )
465
+ . filter_map ( |node| {
466
+ let match_arm = ast:: MatchArm :: cast ( node) ?;
467
+ let match_expr = sema
468
+ . ancestors_with_macros ( match_arm. syntax ( ) . clone ( ) )
469
+ . find_map ( ast:: MatchExpr :: cast) ?;
470
+ let file_id = sema. hir_file_for ( match_expr. syntax ( ) ) ;
471
+ let focus_range = match_arm. fat_arrow_token ( ) ?. text_range ( ) ;
472
+ let match_expr_in_file = InFile :: new ( file_id, match_expr. into ( ) ) ;
473
+ Some ( expr_to_nav ( db, match_expr_in_file, Some ( focus_range) ) )
474
+ } )
475
+ . flatten ( )
476
+ . collect_vec ( ) ,
477
+
478
+ T ! [ if ] => find_branch_root ( sema, token)
479
+ . into_iter ( )
480
+ . filter_map ( |node| {
481
+ let file_id = sema. hir_file_for ( & node) ;
482
+ let if_expr = ast:: IfExpr :: cast ( node) ?;
483
+ let focus_range = if_expr. if_token ( ) ?. text_range ( ) ;
484
+ let if_expr_in_file = InFile :: new ( file_id, if_expr. into ( ) ) ;
485
+ Some ( expr_to_nav ( db, if_expr_in_file, Some ( focus_range) ) )
486
+ } )
487
+ . flatten ( )
488
+ . collect_vec ( ) ,
489
+
490
+ _ => return Some ( Vec :: new ( ) ) ,
491
+ } ;
492
+
493
+ Some ( navs)
494
+ }
495
+
410
496
pub ( crate ) fn find_loops (
411
497
sema : & Semantics < ' _ , RootDatabase > ,
412
498
token : & SyntaxToken ,
@@ -3614,4 +3700,155 @@ fn foo() {
3614
3700
"# ,
3615
3701
) ;
3616
3702
}
3703
+
3704
+ #[ test]
3705
+ fn goto_def_for_match_keyword ( ) {
3706
+ check (
3707
+ r#"
3708
+ fn main() {
3709
+ match$0 0 {
3710
+ // ^^^^^
3711
+ 0 => {},
3712
+ _ => {},
3713
+ }
3714
+ }
3715
+ "# ,
3716
+ ) ;
3717
+ }
3718
+
3719
+ #[ test]
3720
+ fn goto_def_for_match_arm_fat_arrow ( ) {
3721
+ check (
3722
+ r#"
3723
+ fn main() {
3724
+ match 0 {
3725
+ 0 =>$0 {},
3726
+ // ^^
3727
+ _ => {},
3728
+ }
3729
+ }
3730
+ "# ,
3731
+ ) ;
3732
+ }
3733
+
3734
+ #[ test]
3735
+ fn goto_def_for_if_keyword ( ) {
3736
+ check (
3737
+ r#"
3738
+ fn main() {
3739
+ if$0 true {
3740
+ // ^^
3741
+ ()
3742
+ }
3743
+ }
3744
+ "# ,
3745
+ ) ;
3746
+ }
3747
+
3748
+ #[ test]
3749
+ fn goto_def_for_match_nested_in_if ( ) {
3750
+ check (
3751
+ r#"
3752
+ fn main() {
3753
+ if true {
3754
+ match$0 0 {
3755
+ // ^^^^^
3756
+ 0 => {},
3757
+ _ => {},
3758
+ }
3759
+ }
3760
+ }
3761
+ "# ,
3762
+ ) ;
3763
+ }
3764
+
3765
+ #[ test]
3766
+ fn goto_def_for_multiple_match_expressions ( ) {
3767
+ check (
3768
+ r#"
3769
+ fn main() {
3770
+ match 0 {
3771
+ 0 => {},
3772
+ _ => {},
3773
+ };
3774
+
3775
+ match$0 1 {
3776
+ // ^^^^^
3777
+ 1 => {},
3778
+ _ => {},
3779
+ }
3780
+ }
3781
+ "# ,
3782
+ ) ;
3783
+ }
3784
+
3785
+ #[ test]
3786
+ fn goto_def_for_nested_match_expressions ( ) {
3787
+ check (
3788
+ r#"
3789
+ fn main() {
3790
+ match 0 {
3791
+ 0 => match$0 1 {
3792
+ // ^^^^^
3793
+ 1 => {},
3794
+ _ => {},
3795
+ },
3796
+ _ => {},
3797
+ }
3798
+ }
3799
+ "# ,
3800
+ ) ;
3801
+ }
3802
+
3803
+ #[ test]
3804
+ fn goto_def_for_if_else_chains ( ) {
3805
+ check (
3806
+ r#"
3807
+ fn main() {
3808
+ if true {
3809
+ // ^^
3810
+ ()
3811
+ } else if$0 false {
3812
+ ()
3813
+ } else {
3814
+ ()
3815
+ }
3816
+ }
3817
+ "# ,
3818
+ ) ;
3819
+ }
3820
+
3821
+ #[ test]
3822
+ fn goto_def_for_match_with_guards ( ) {
3823
+ check (
3824
+ r#"
3825
+ fn main() {
3826
+ match 42 {
3827
+ x if x > 0 =>$0 {},
3828
+ // ^^
3829
+ _ => {},
3830
+ }
3831
+ }
3832
+ "# ,
3833
+ ) ;
3834
+ }
3835
+
3836
+ #[ test]
3837
+ fn goto_def_for_match_with_macro_arm ( ) {
3838
+ check (
3839
+ r#"
3840
+ macro_rules! arm {
3841
+ () => { 0 => {} };
3842
+ }
3843
+
3844
+ fn main() {
3845
+ match$0 0 {
3846
+ // ^^^^^
3847
+ arm!(),
3848
+ _ => {},
3849
+ }
3850
+ }
3851
+ "# ,
3852
+ ) ;
3853
+ }
3617
3854
}
0 commit comments