Skip to content

Commit 7a14800

Browse files
committed
feat: find references on control-flow kws
1 parent 5c39c85 commit 7a14800

File tree

1 file changed

+253
-1
lines changed

1 file changed

+253
-1
lines changed

src/tools/rust-analyzer/crates/ide/src/references.rs

Lines changed: 253 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use syntax::{
2424
SyntaxNode, TextRange, TextSize, T,
2525
};
2626

27-
use crate::{FilePosition, NavigationTarget, TryToNav};
27+
use crate::{highlight_related, FilePosition, HighlightedRange, NavigationTarget, TryToNav};
2828

2929
#[derive(Debug, Clone)]
3030
pub struct ReferenceSearchResult {
@@ -103,6 +103,11 @@ pub(crate) fn find_all_refs(
103103
}
104104
};
105105

106+
// Find references for control-flow keywords.
107+
if let Some(res) = handle_control_flow_keywords(sema, position) {
108+
return Some(vec![res]);
109+
}
110+
106111
match name_for_constructor_search(&syntax, position) {
107112
Some(name) => {
108113
let def = match NameClass::classify(sema, &name)? {
@@ -296,6 +301,34 @@ fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool {
296301
}).unwrap_or(false)
297302
}
298303

304+
fn handle_control_flow_keywords(
305+
sema: &Semantics<'_, RootDatabase>,
306+
FilePosition { file_id, offset }: FilePosition,
307+
) -> Option<ReferenceSearchResult> {
308+
let file = sema.parse(file_id);
309+
let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword())?;
310+
311+
let refs = match token.kind() {
312+
T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token)?,
313+
T![async] => highlight_related::highlight_yield_points(sema, token)?,
314+
T![loop] | T![while] | T![break] | T![continue] => {
315+
highlight_related::highlight_break_points(sema, token)?
316+
}
317+
T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
318+
highlight_related::highlight_break_points(sema, token)?
319+
}
320+
_ => return None,
321+
}
322+
.into_iter()
323+
.map(|HighlightedRange { range, category }| (range, category))
324+
.collect();
325+
326+
Some(ReferenceSearchResult {
327+
declaration: None,
328+
references: IntMap::from_iter([(file_id, refs)]),
329+
})
330+
}
331+
299332
#[cfg(test)]
300333
mod tests {
301334
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

Comments
 (0)