@@ -281,99 +281,95 @@ fn highlight_references(
281
281
}
282
282
}
283
283
284
- // If `file_id` is None,
285
- pub ( crate ) fn highlight_exit_points (
284
+ fn hl_exit_points (
286
285
sema : & Semantics < ' _ , RootDatabase > ,
287
- token : SyntaxToken ,
288
- ) -> FxHashMap < EditionedFileId , Vec < HighlightedRange > > {
289
- fn hl (
290
- sema : & Semantics < ' _ , RootDatabase > ,
291
- def_token : Option < SyntaxToken > ,
292
- body : ast:: Expr ,
293
- ) -> Option < FxHashMap < EditionedFileId , FxHashSet < HighlightedRange > > > {
294
- let mut highlights: FxHashMap < EditionedFileId , FxHashSet < _ > > = FxHashMap :: default ( ) ;
286
+ def_token : Option < SyntaxToken > ,
287
+ body : ast:: Expr ,
288
+ ) -> Option < FxHashMap < EditionedFileId , FxHashSet < HighlightedRange > > > {
289
+ let mut highlights: FxHashMap < EditionedFileId , FxHashSet < _ > > = FxHashMap :: default ( ) ;
290
+
291
+ let mut push_to_highlights = |file_id, range| {
292
+ if let Some ( FileRange { file_id, range } ) = original_frange ( sema. db , file_id, range) {
293
+ let hrange = HighlightedRange { category : ReferenceCategory :: empty ( ) , range } ;
294
+ highlights. entry ( file_id) . or_default ( ) . insert ( hrange) ;
295
+ }
296
+ } ;
295
297
296
- let mut push_to_highlights = |file_id, range| {
297
- if let Some ( FileRange { file_id, range } ) = original_frange ( sema. db , file_id, range) {
298
- let hrange = HighlightedRange { category : ReferenceCategory :: empty ( ) , range } ;
299
- highlights. entry ( file_id) . or_default ( ) . insert ( hrange) ;
298
+ if let Some ( tok) = def_token {
299
+ let file_id = sema. hir_file_for ( & tok. parent ( ) ?) ;
300
+ let range = Some ( tok. text_range ( ) ) ;
301
+ push_to_highlights ( file_id, range) ;
302
+ }
303
+
304
+ WalkExpandedExprCtx :: new ( sema) . walk ( & body, & mut |_, expr| {
305
+ let file_id = sema. hir_file_for ( expr. syntax ( ) ) ;
306
+
307
+ let range = match & expr {
308
+ ast:: Expr :: TryExpr ( try_) => try_. question_mark_token ( ) . map ( |token| token. text_range ( ) ) ,
309
+ ast:: Expr :: MethodCallExpr ( _) | ast:: Expr :: CallExpr ( _) | ast:: Expr :: MacroExpr ( _)
310
+ if sema. type_of_expr ( & expr) . map_or ( false , |ty| ty. original . is_never ( ) ) =>
311
+ {
312
+ Some ( expr. syntax ( ) . text_range ( ) )
300
313
}
314
+ _ => None ,
301
315
} ;
302
316
303
- if let Some ( tok) = def_token {
304
- let file_id = sema. hir_file_for ( & tok. parent ( ) ?) ;
305
- let range = Some ( tok. text_range ( ) ) ;
306
- push_to_highlights ( file_id, range) ;
307
- }
317
+ push_to_highlights ( file_id, range) ;
318
+ } ) ;
308
319
309
- WalkExpandedExprCtx :: new ( sema) . walk ( & body, & mut |_, expr| {
320
+ // We should handle `return` separately, because when it is used in a `try` block,
321
+ // it will exit the outside function instead of the block itself.
322
+ WalkExpandedExprCtx :: new ( sema)
323
+ . with_check_ctx ( & WalkExpandedExprCtx :: is_async_const_block_or_closure)
324
+ . walk ( & body, & mut |_, expr| {
310
325
let file_id = sema. hir_file_for ( expr. syntax ( ) ) ;
311
326
312
327
let range = match & expr {
313
- ast:: Expr :: TryExpr ( try_) => {
314
- try_. question_mark_token ( ) . map ( |token| token. text_range ( ) )
315
- }
316
- ast:: Expr :: MethodCallExpr ( _) | ast:: Expr :: CallExpr ( _) | ast:: Expr :: MacroExpr ( _)
317
- if sema. type_of_expr ( & expr) . map_or ( false , |ty| ty. original . is_never ( ) ) =>
318
- {
319
- Some ( expr. syntax ( ) . text_range ( ) )
320
- }
328
+ ast:: Expr :: ReturnExpr ( expr) => expr. return_token ( ) . map ( |token| token. text_range ( ) ) ,
321
329
_ => None ,
322
330
} ;
323
331
324
332
push_to_highlights ( file_id, range) ;
325
333
} ) ;
326
334
327
- // We should handle `return` separately, because when it is used in a `try` block,
328
- // it will exit the outside function instead of the block itself.
329
- WalkExpandedExprCtx :: new ( sema)
330
- . with_check_ctx ( & WalkExpandedExprCtx :: is_async_const_block_or_closure)
331
- . walk ( & body, & mut |_, expr| {
332
- let file_id = sema. hir_file_for ( expr. syntax ( ) ) ;
333
-
334
- let range = match & expr {
335
- ast:: Expr :: ReturnExpr ( expr) => {
336
- expr. return_token ( ) . map ( |token| token. text_range ( ) )
337
- }
338
- _ => None ,
339
- } ;
340
-
341
- push_to_highlights ( file_id, range) ;
342
- } ) ;
343
-
344
- let tail = match body {
345
- ast:: Expr :: BlockExpr ( b) => b. tail_expr ( ) ,
346
- e => Some ( e) ,
347
- } ;
335
+ let tail = match body {
336
+ ast:: Expr :: BlockExpr ( b) => b. tail_expr ( ) ,
337
+ e => Some ( e) ,
338
+ } ;
348
339
349
- if let Some ( tail) = tail {
350
- for_each_tail_expr ( & tail, & mut |tail| {
351
- let file_id = sema. hir_file_for ( tail. syntax ( ) ) ;
352
- let range = match tail {
353
- ast:: Expr :: BreakExpr ( b) => b
354
- . break_token ( )
355
- . map_or_else ( || tail. syntax ( ) . text_range ( ) , |tok| tok. text_range ( ) ) ,
356
- _ => tail. syntax ( ) . text_range ( ) ,
357
- } ;
358
- push_to_highlights ( file_id, Some ( range) ) ;
359
- } ) ;
360
- }
361
- Some ( highlights)
340
+ if let Some ( tail) = tail {
341
+ for_each_tail_expr ( & tail, & mut |tail| {
342
+ let file_id = sema. hir_file_for ( tail. syntax ( ) ) ;
343
+ let range = match tail {
344
+ ast:: Expr :: BreakExpr ( b) => b
345
+ . break_token ( )
346
+ . map_or_else ( || tail. syntax ( ) . text_range ( ) , |tok| tok. text_range ( ) ) ,
347
+ _ => tail. syntax ( ) . text_range ( ) ,
348
+ } ;
349
+ push_to_highlights ( file_id, Some ( range) ) ;
350
+ } ) ;
362
351
}
352
+ Some ( highlights)
353
+ }
363
354
355
+ // If `file_id` is None,
356
+ pub ( crate ) fn highlight_exit_points (
357
+ sema : & Semantics < ' _ , RootDatabase > ,
358
+ token : SyntaxToken ,
359
+ ) -> FxHashMap < EditionedFileId , Vec < HighlightedRange > > {
364
360
let mut res = FxHashMap :: default ( ) ;
365
361
for def in goto_definition:: find_fn_or_blocks ( sema, & token) {
366
362
let new_map = match_ast ! {
367
363
match def {
368
- ast:: Fn ( fn_) => fn_. body( ) . and_then( |body| hl ( sema, fn_. fn_token( ) , body. into( ) ) ) ,
364
+ ast:: Fn ( fn_) => fn_. body( ) . and_then( |body| hl_exit_points ( sema, fn_. fn_token( ) , body. into( ) ) ) ,
369
365
ast:: ClosureExpr ( closure) => {
370
366
let pipe_tok = closure. param_list( ) . and_then( |p| p. pipe_token( ) ) ;
371
- closure. body( ) . and_then( |body| hl ( sema, pipe_tok, body) )
367
+ closure. body( ) . and_then( |body| hl_exit_points ( sema, pipe_tok, body) )
372
368
} ,
373
369
ast:: BlockExpr ( blk) => match blk. modifier( ) {
374
- Some ( ast:: BlockModifier :: Async ( t) ) => hl ( sema, Some ( t) , blk. into( ) ) ,
370
+ Some ( ast:: BlockModifier :: Async ( t) ) => hl_exit_points ( sema, Some ( t) , blk. into( ) ) ,
375
371
Some ( ast:: BlockModifier :: Try ( t) ) if token. kind( ) != T ![ return ] => {
376
- hl ( sema, Some ( t) , blk. into( ) )
372
+ hl_exit_points ( sema, Some ( t) , blk. into( ) )
377
373
} ,
378
374
_ => continue ,
379
375
} ,
@@ -517,10 +513,23 @@ pub(crate) fn highlight_yield_points(
517
513
match anc {
518
514
ast:: Fn ( fn_) => hl( sema, fn_. async_token( ) , fn_. body( ) . map( ast:: Expr :: BlockExpr ) ) ,
519
515
ast:: BlockExpr ( block_expr) => {
520
- if block_expr. async_token( ) . is_none ( ) {
516
+ let Some ( async_token ) = block_expr. async_token( ) else {
521
517
continue ;
518
+ } ;
519
+
520
+ // Async blocks act similar to closures. So we want to
521
+ // highlight their exit points too, but only if we are on
522
+ // the async token.
523
+ if async_token == token {
524
+ let exit_points = hl_exit_points(
525
+ sema,
526
+ Some ( async_token. clone( ) ) ,
527
+ block_expr. clone( ) . into( ) ,
528
+ ) ;
529
+ merge_map( & mut res, exit_points) ;
522
530
}
523
- hl( sema, block_expr. async_token( ) , Some ( block_expr. into( ) ) )
531
+
532
+ hl( sema, Some ( async_token) , Some ( block_expr. into( ) ) )
524
533
} ,
525
534
ast:: ClosureExpr ( closure) => hl( sema, closure. async_token( ) , closure. body( ) ) ,
526
535
_ => continue ,
@@ -876,6 +885,27 @@ pub async$0 fn foo() {
876
885
) ;
877
886
}
878
887
888
+ #[ test]
889
+ fn test_hl_exit_points_of_async_blocks ( ) {
890
+ check (
891
+ r#"
892
+ pub fn foo() {
893
+ let x = async$0 {
894
+ // ^^^^^
895
+ 0.await;
896
+ // ^^^^^
897
+ 0?;
898
+ // ^
899
+ return 0;
900
+ // ^^^^^^
901
+ 0
902
+ // ^
903
+ };
904
+ }
905
+ "# ,
906
+ ) ;
907
+ }
908
+
879
909
#[ test]
880
910
fn test_hl_let_else_yield_points ( ) {
881
911
check (
@@ -925,11 +955,9 @@ async fn foo() {
925
955
async fn foo() {
926
956
(async {
927
957
// ^^^^^
928
- (async {
929
- 0.await
930
- }).await$0 }
931
- // ^^^^^
932
- ).await;
958
+ (async { 0.await }).await$0
959
+ // ^^^^^
960
+ }).await;
933
961
}
934
962
"# ,
935
963
) ;
0 commit comments