@@ -25,7 +25,7 @@ use syntax::{
2525    SyntaxNode ,  TextRange ,  TextSize ,  T , 
2626} ; 
2727
28- use  crate :: { FilePosition ,  NavigationTarget ,  TryToNav } ; 
28+ use  crate :: { highlight_related ,   FilePosition ,   HighlightedRange ,  NavigationTarget ,  TryToNav } ; 
2929
3030#[ derive( Debug ,  Clone ) ]  
3131pub  struct  ReferenceSearchResult  { 
@@ -104,6 +104,11 @@ pub(crate) fn find_all_refs(
104104        } 
105105    } ; 
106106
107+     // Find references for control-flow keywords. 
108+     if  let  Some ( res)  = handle_control_flow_keywords ( sema,  position)  { 
109+         return  Some ( vec ! [ res] ) ; 
110+     } 
111+ 
107112    match  name_for_constructor_search ( & syntax,  position)  { 
108113        Some ( name)  => { 
109114            let  def = match  NameClass :: classify ( sema,  & name) ? { 
@@ -297,6 +302,34 @@ fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
297302    } ) . unwrap_or ( false ) 
298303} 
299304
305+ fn  handle_control_flow_keywords ( 
306+     sema :  & Semantics < ' _ ,  RootDatabase > , 
307+     FilePosition  {  file_id,  offset } :  FilePosition , 
308+ )  -> Option < ReferenceSearchResult >  { 
309+     let  file = sema. parse ( file_id) ; 
310+     let  token = file. syntax ( ) . token_at_offset ( offset) . find ( |t| t. kind ( ) . is_keyword ( ) ) ?; 
311+ 
312+     let  refs = match  token. kind ( )  { 
313+         T ! [ fn ]  | T ! [ return ]  | T ! [ try]  => highlight_related:: highlight_exit_points ( sema,  token) ?, 
314+         T ! [ async ]  => highlight_related:: highlight_yield_points ( sema,  token) ?, 
315+         T ! [ loop ]  | T ! [ while ]  | T ! [ break ]  | T ! [ continue ]  => { 
316+             highlight_related:: highlight_break_points ( sema,  token) ?
317+         } 
318+         T ! [ for ]  if  token. parent ( ) . and_then ( ast:: ForExpr :: cast) . is_some ( )  => { 
319+             highlight_related:: highlight_break_points ( sema,  token) ?
320+         } 
321+         _ => return  None , 
322+     } 
323+     . into_iter ( ) 
324+     . map ( |HighlightedRange  {  range,  category } | ( range,  category) ) 
325+     . collect ( ) ; 
326+ 
327+     Some ( ReferenceSearchResult  { 
328+         declaration :  None , 
329+         references :  IntMap :: from_iter ( [ ( file_id,  refs) ] ) , 
330+     } ) 
331+ } 
332+ 
300333#[ cfg( test) ]  
301334mod  tests { 
302335    use  expect_test:: { expect,  Expect } ; 
@@ -2187,4 +2220,223 @@ fn test() {
21872220            "# ] ] , 
21882221        ) ; 
21892222    } 
2223+ 
2224+     #[ test]  
2225+     fn  goto_ref_fn_kw ( )  { 
2226+         check ( 
2227+             r#" 
2228+ macro_rules! N { 
2229+     ($i:ident, $x:expr, $blk:expr) => { 
2230+         for $i in 0..$x { 
2231+             $blk 
2232+         } 
2233+     }; 
2234+ } 
2235+ 
2236+ fn main() { 
2237+     $0fn f() { 
2238+         N!(i, 5, { 
2239+             println!("{}", i); 
2240+             return; 
2241+         }); 
2242+ 
2243+         for i in 1..5 { 
2244+             return; 
2245+         } 
2246+ 
2247+        (|| { 
2248+             return; 
2249+         })(); 
2250+     } 
2251+ } 
2252+ "# , 
2253+             expect ! [ [ r#" 
2254+                 FileId(0) 136..138 
2255+                 FileId(0) 207..213 
2256+                 FileId(0) 264..270 
2257+             "# ] ] , 
2258+         ) 
2259+     } 
2260+ 
2261+     #[ test]  
2262+     fn  goto_ref_exit_points ( )  { 
2263+         check ( 
2264+             r#" 
2265+ fn$0 foo() -> u32 { 
2266+     if true { 
2267+         return 0; 
2268+     } 
2269+ 
2270+     0?; 
2271+     0xDEAD_BEEF 
2272+ } 
2273+ "# , 
2274+             expect ! [ [ r#" 
2275+                 FileId(0) 0..2 
2276+                 FileId(0) 62..63 
2277+                 FileId(0) 40..46 
2278+                 FileId(0) 69..80 
2279+             "# ] ] , 
2280+         ) ; 
2281+     } 
2282+ 
2283+     #[ test]  
2284+     fn  test_ref_yield_points ( )  { 
2285+         check ( 
2286+             r#" 
2287+ pub async$0 fn foo() { 
2288+     let x = foo() 
2289+         .await 
2290+         .await; 
2291+     || { 0.await }; 
2292+     (async { 0.await }).await 
2293+ } 
2294+ "# , 
2295+             expect ! [ [ r#" 
2296+                 FileId(0) 4..9 
2297+                 FileId(0) 63..68 
2298+                 FileId(0) 48..53 
2299+                 FileId(0) 114..119 
2300+             "# ] ] , 
2301+         ) ; 
2302+     } 
2303+ 
2304+     #[ test]  
2305+     fn  goto_ref_for_kw ( )  { 
2306+         check ( 
2307+             r#" 
2308+ fn main() { 
2309+     $0for i in 1..5 { 
2310+         break; 
2311+         continue; 
2312+     } 
2313+ } 
2314+ "# , 
2315+             expect ! [ [ r#" 
2316+                 FileId(0) 16..19 
2317+                 FileId(0) 40..45 
2318+                 FileId(0) 55..63 
2319+             "# ] ] , 
2320+         ) 
2321+     } 
2322+ 
2323+     #[ test]  
2324+     fn  goto_ref_on_break_kw ( )  { 
2325+         check ( 
2326+             r#" 
2327+ fn main() { 
2328+     for i in 1..5 { 
2329+         $0break; 
2330+         continue; 
2331+     } 
2332+ } 
2333+ "# , 
2334+             expect ! [ [ r#" 
2335+                 FileId(0) 16..19 
2336+                 FileId(0) 40..45 
2337+             "# ] ] , 
2338+         ) 
2339+     } 
2340+ 
2341+     #[ test]  
2342+     fn  goto_ref_on_break_kw_for_block ( )  { 
2343+         check ( 
2344+             r#" 
2345+ fn main() { 
2346+     'a:{ 
2347+         $0break 'a; 
2348+     } 
2349+ } 
2350+ "# , 
2351+             expect ! [ [ r#" 
2352+                 FileId(0) 16..19 
2353+                 FileId(0) 29..37 
2354+             "# ] ] , 
2355+         ) 
2356+     } 
2357+ 
2358+     #[ test]  
2359+     fn  goto_ref_on_break_with_label ( )  { 
2360+         check ( 
2361+             r#" 
2362+ fn foo() { 
2363+     'outer: loop { 
2364+          break; 
2365+          'inner: loop { 
2366+             'innermost: loop { 
2367+             } 
2368+             $0break 'outer; 
2369+             break; 
2370+         } 
2371+         break; 
2372+     } 
2373+ } 
2374+ "# , 
2375+             expect ! [ [ r#" 
2376+                 FileId(0) 15..27 
2377+                 FileId(0) 39..44 
2378+                 FileId(0) 127..139 
2379+                 FileId(0) 178..183 
2380+             "# ] ] , 
2381+         ) ; 
2382+     } 
2383+ 
2384+     #[ test]  
2385+     fn  goto_ref_on_return_in_try ( )  { 
2386+         check ( 
2387+             r#" 
2388+ fn main() { 
2389+     fn f() { 
2390+         try { 
2391+             $0return; 
2392+         } 
2393+ 
2394+         return; 
2395+     } 
2396+     return; 
2397+ } 
2398+ "# , 
2399+             expect ! [ [ r#" 
2400+                 FileId(0) 16..18 
2401+                 FileId(0) 51..57 
2402+                 FileId(0) 78..84 
2403+             "# ] ] , 
2404+         ) 
2405+     } 
2406+ 
2407+     #[ test]  
2408+     fn  goto_ref_on_break_in_try ( )  { 
2409+         check ( 
2410+             r#" 
2411+ fn main() { 
2412+     for i in 1..100 { 
2413+         let x: Result<(), ()> = try { 
2414+             $0break; 
2415+         }; 
2416+     } 
2417+ } 
2418+ "# , 
2419+             expect ! [ [ r#" 
2420+                 FileId(0) 16..19 
2421+                 FileId(0) 84..89 
2422+             "# ] ] , 
2423+         ) 
2424+     } 
2425+ 
2426+     #[ test]  
2427+     fn  goto_ref_on_return_in_async_block ( )  { 
2428+         check ( 
2429+             r#" 
2430+ fn main() { 
2431+     $0async { 
2432+         return; 
2433+     } 
2434+ } 
2435+ "# , 
2436+             expect ! [ [ r#" 
2437+                 FileId(0) 16..21 
2438+                 FileId(0) 32..38 
2439+             "# ] ] , 
2440+         ) 
2441+     } 
21902442} 
0 commit comments