@@ -291,13 +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_branch_exit_points ( sema, token) ,
301302 _ => None ,
302303 }
303304}
@@ -407,6 +408,91 @@ fn nav_for_exit_points(
407408 Some ( navs)
408409}
409410
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+
410496pub ( crate ) fn find_loops (
411497 sema : & Semantics < ' _ , RootDatabase > ,
412498 token : & SyntaxToken ,
@@ -3614,4 +3700,155 @@ fn foo() {
36143700 "# ,
36153701 ) ;
36163702 }
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+ }
36173854}
0 commit comments