1
1
use std:: cell:: OnceCell ;
2
2
3
3
use rustc_data_structures:: graph:: WithNumNodes ;
4
+ use rustc_index:: bit_set:: BitSet ;
4
5
use 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 } ;
6
8
use rustc_span:: { BytePos , ExpnKind , MacroKind , Span , Symbol , DUMMY_SP } ;
7
9
8
10
use super :: graph:: { BasicCoverageBlock , CoverageGraph , START_BCB } ;
9
11
10
12
mod from_mir;
11
13
14
+ pub ( super ) struct BcbBranchSpan {
15
+ pub ( super ) span : Span ,
16
+ pub ( super ) true_bcb : BasicCoverageBlock ,
17
+ pub ( super ) false_bcb : BasicCoverageBlock ,
18
+ }
19
+
12
20
pub ( super ) struct CoverageSpans {
13
21
/// Map from BCBs to their list of coverage spans.
14
22
bcb_to_spans : IndexVec < BasicCoverageBlock , Vec < Span > > ,
23
+
24
+ bcbs_with_branch_spans : BitSet < BasicCoverageBlock > ,
25
+ branch_spans : Vec < BcbBranchSpan > ,
15
26
}
16
27
17
28
impl CoverageSpans {
@@ -34,16 +45,57 @@ impl CoverageSpans {
34
45
bcb_to_spans[ bcb] . push ( span) ;
35
46
}
36
47
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 }
38
86
}
39
87
40
88
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 )
42
90
}
43
91
44
92
pub ( super ) fn spans_for_bcb ( & self , bcb : BasicCoverageBlock ) -> & [ Span ] {
45
93
& self . bcb_to_spans [ bcb]
46
94
}
95
+
96
+ pub ( super ) fn branch_spans ( & self ) -> & [ BcbBranchSpan ] {
97
+ & self . branch_spans
98
+ }
47
99
}
48
100
49
101
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
0 commit comments