@@ -394,7 +394,9 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
394
394
struct ExtractedHirInfo {
395
395
function_source_hash : u64 ,
396
396
is_async_fn : bool ,
397
- fn_sig_span : Span ,
397
+ /// The span of the function's signature, extended to the start of `body_span`.
398
+ /// Must have the same context and filename as the body span.
399
+ fn_sig_span_extended : Option < Span > ,
398
400
body_span : Span ,
399
401
}
400
402
@@ -407,13 +409,25 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
407
409
hir:: map:: associated_body ( hir_node) . expect ( "HIR node is a function with body" ) ;
408
410
let hir_body = tcx. hir ( ) . body ( fn_body_id) ;
409
411
410
- let is_async_fn = hir_node. fn_sig ( ) . is_some_and ( |fn_sig| fn_sig. header . is_async ( ) ) ;
411
- let body_span = get_body_span ( tcx, hir_body, def_id) ;
412
+ let maybe_fn_sig = hir_node. fn_sig ( ) ;
413
+ let is_async_fn = maybe_fn_sig. is_some_and ( |fn_sig| fn_sig. header . is_async ( ) ) ;
414
+
415
+ let mut body_span = hir_body. value . span ;
416
+
417
+ use rustc_hir:: { Closure , Expr , ExprKind , Node } ;
418
+ // Unexpand a closure's body span back to the context of its declaration.
419
+ // This helps with closure bodies that consist of just a single bang-macro,
420
+ // and also with closure bodies produced by async desugaring.
421
+ if let Node :: Expr ( & Expr { kind : ExprKind :: Closure ( & Closure { fn_decl_span, .. } ) , .. } ) =
422
+ hir_node
423
+ {
424
+ body_span = body_span. find_ancestor_in_same_ctxt ( fn_decl_span) . unwrap_or ( body_span) ;
425
+ }
412
426
413
427
// The actual signature span is only used if it has the same context and
414
428
// filename as the body, and precedes the body.
415
- let maybe_fn_sig_span = hir_node . fn_sig ( ) . map ( |fn_sig| fn_sig . span ) ;
416
- let fn_sig_span = maybe_fn_sig_span
429
+ let fn_sig_span_extended = maybe_fn_sig
430
+ . map ( |fn_sig| fn_sig . span )
417
431
. filter ( |& fn_sig_span| {
418
432
let source_map = tcx. sess . source_map ( ) ;
419
433
let file_idx = |span : Span | source_map. lookup_source_file_idx ( span. lo ( ) ) ;
@@ -423,30 +437,11 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
423
437
&& file_idx ( fn_sig_span) == file_idx ( body_span)
424
438
} )
425
439
// If so, extend it to the start of the body span.
426
- . map ( |fn_sig_span| fn_sig_span. with_hi ( body_span. lo ( ) ) )
427
- // Otherwise, create a dummy signature span at the start of the body.
428
- . unwrap_or_else ( || body_span. shrink_to_lo ( ) ) ;
440
+ . map ( |fn_sig_span| fn_sig_span. with_hi ( body_span. lo ( ) ) ) ;
429
441
430
442
let function_source_hash = hash_mir_source ( tcx, hir_body) ;
431
443
432
- ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
433
- }
434
-
435
- fn get_body_span < ' tcx > (
436
- tcx : TyCtxt < ' tcx > ,
437
- hir_body : & rustc_hir:: Body < ' tcx > ,
438
- def_id : LocalDefId ,
439
- ) -> Span {
440
- let mut body_span = hir_body. value . span ;
441
-
442
- if tcx. is_closure_or_coroutine ( def_id. to_def_id ( ) ) {
443
- // If the current function is a closure, and its "body" span was created
444
- // by macro expansion or compiler desugaring, try to walk backwards to
445
- // the pre-expansion call site or body.
446
- body_span = body_span. source_callsite ( ) ;
447
- }
448
-
449
- body_span
444
+ ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span_extended, body_span }
450
445
}
451
446
452
447
fn hash_mir_source < ' tcx > ( tcx : TyCtxt < ' tcx > , hir_body : & ' tcx rustc_hir:: Body < ' tcx > ) -> u64 {
0 commit comments