11use std:: cell:: OnceCell ;
22
33use rustc_data_structures:: graph:: WithNumNodes ;
4+ use rustc_index:: bit_set:: BitSet ;
45use rustc_index:: IndexVec ;
5- use rustc_middle:: mir;
6+ use rustc_middle:: mir:: coverage:: { BlockMarkerId , BranchSpan , CoverageKind } ;
7+ use rustc_middle:: mir:: { self , BasicBlock , StatementKind } ;
68use rustc_span:: { BytePos , ExpnKind , MacroKind , Span , Symbol , DUMMY_SP } ;
79
810use super :: graph:: { BasicCoverageBlock , CoverageGraph , START_BCB } ;
911
1012mod from_mir;
1113
14+ pub ( super ) struct BcbBranchSpan {
15+ pub ( super ) span : Span ,
16+ pub ( super ) true_bcb : BasicCoverageBlock ,
17+ pub ( super ) false_bcb : BasicCoverageBlock ,
18+ }
19+
1220pub ( super ) struct CoverageSpans {
1321 /// Map from BCBs to their list of coverage spans.
1422 bcb_to_spans : IndexVec < BasicCoverageBlock , Vec < Span > > ,
23+
24+ bcbs_with_branch_spans : BitSet < BasicCoverageBlock > ,
25+ branch_spans : Vec < BcbBranchSpan > ,
1526}
1627
1728impl CoverageSpans {
@@ -34,16 +45,57 @@ impl CoverageSpans {
3445 bcb_to_spans[ bcb] . push ( span) ;
3546 }
3647
37- Self { bcb_to_spans }
48+ let mut bcbs_with_branch_spans = BitSet :: new_empty ( basic_coverage_blocks. num_nodes ( ) ) ;
49+ let mut branch_spans = Vec :: new ( ) ;
50+
51+ if let Some ( coverage_hir_info) = mir_body. coverage_hir_info . as_deref ( ) {
52+ let mut block_markers = IndexVec :: < BlockMarkerId , Option < BasicBlock > > :: from_elem_n (
53+ None ,
54+ coverage_hir_info. num_block_markers ,
55+ ) ;
56+
57+ for ( bb, data) in mir_body. basic_blocks . iter_enumerated ( ) {
58+ for statement in & data. statements {
59+ if let StatementKind :: Coverage ( coverage) = & statement. kind {
60+ if let CoverageKind :: BlockMarker { id } = coverage. kind {
61+ block_markers[ id] = Some ( bb) ;
62+ }
63+ }
64+ }
65+ }
66+
67+ // Assume that most branch spans will resolve successfully.
68+ branch_spans. reserve ( coverage_hir_info. branch_spans . len ( ) ) ;
69+ branch_spans. extend ( coverage_hir_info. branch_spans . iter ( ) . filter_map (
70+ |& BranchSpan { span, true_marker, false_marker } | {
71+ let bcb_from_marker = |marker : BlockMarkerId | {
72+ Some ( basic_coverage_blocks. bcb_from_bb ( block_markers[ marker] ?) ?)
73+ } ;
74+
75+ let true_bcb = bcb_from_marker ( true_marker) ?;
76+ let false_bcb = bcb_from_marker ( false_marker) ?;
77+
78+ bcbs_with_branch_spans. insert ( true_bcb) ;
79+ bcbs_with_branch_spans. insert ( false_bcb) ;
80+ Some ( BcbBranchSpan { span, true_bcb, false_bcb } )
81+ } ,
82+ ) ) ;
83+ }
84+
85+ Self { bcb_to_spans, bcbs_with_branch_spans, branch_spans }
3886 }
3987
4088 pub ( super ) fn bcb_has_coverage_spans ( & self , bcb : BasicCoverageBlock ) -> bool {
41- !self . bcb_to_spans [ bcb] . is_empty ( )
89+ !self . bcb_to_spans [ bcb] . is_empty ( ) || self . bcbs_with_branch_spans . contains ( bcb )
4290 }
4391
4492 pub ( super ) fn spans_for_bcb ( & self , bcb : BasicCoverageBlock ) -> & [ Span ] {
4593 & self . bcb_to_spans [ bcb]
4694 }
95+
96+ pub ( super ) fn branch_spans ( & self ) -> & [ BcbBranchSpan ] {
97+ & self . branch_spans
98+ }
4799}
48100
49101/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
0 commit comments