1
1
use std:: assert_matches:: assert_matches;
2
2
use std:: collections:: hash_map:: Entry ;
3
- use std:: collections:: VecDeque ;
3
+ use std:: collections:: { BTreeMap , VecDeque } ;
4
4
5
5
use rustc_data_structures:: fx:: FxHashMap ;
6
6
use rustc_middle:: mir:: coverage:: {
7
7
BlockMarkerId , BranchSpan , ConditionId , ConditionInfo , CoverageKind , MCDCBranchSpan ,
8
- MCDCDecisionSpan ,
8
+ MCDCDecisionSpan , MCDCMatchBranchSpan ,
9
9
} ;
10
- use rustc_middle:: mir:: { self , BasicBlock , SourceInfo , UnOp } ;
10
+ use rustc_middle:: mir:: { self , BasicBlock , SourceInfo , StatementKind , UnOp } ;
11
11
use rustc_middle:: thir:: { ExprId , ExprKind , LogicalOp , Thir } ;
12
12
use rustc_middle:: ty:: TyCtxt ;
13
13
use rustc_span:: def_id:: LocalDefId ;
@@ -22,7 +22,8 @@ pub(crate) struct BranchInfoBuilder {
22
22
23
23
num_block_markers : usize ,
24
24
branch_spans : Vec < BranchSpan > ,
25
-
25
+ pattern_match_branch_records : BTreeMap < Span , MCDCMatchBranchSpan > ,
26
+ markers_map : BTreeMap < usize , BasicBlock > ,
26
27
mcdc_branch_spans : Vec < MCDCBranchSpan > ,
27
28
mcdc_decision_spans : Vec < MCDCDecisionSpan > ,
28
29
mcdc_state : Option < MCDCState > ,
@@ -47,6 +48,8 @@ impl BranchInfoBuilder {
47
48
nots : FxHashMap :: default ( ) ,
48
49
num_block_markers : 0 ,
49
50
branch_spans : vec ! [ ] ,
51
+ pattern_match_branch_records : BTreeMap :: new ( ) ,
52
+ markers_map : Default :: default ( ) ,
50
53
mcdc_branch_spans : vec ! [ ] ,
51
54
mcdc_decision_spans : vec ! [ ] ,
52
55
mcdc_state : MCDCState :: new_if_enabled ( tcx) ,
@@ -175,6 +178,8 @@ impl BranchInfoBuilder {
175
178
nots : _,
176
179
num_block_markers,
177
180
branch_spans,
181
+ pattern_match_branch_records,
182
+ markers_map : _,
178
183
mcdc_branch_spans,
179
184
mcdc_decision_spans,
180
185
mcdc_state : _,
@@ -184,11 +189,24 @@ impl BranchInfoBuilder {
184
189
assert ! ( branch_spans. is_empty( ) ) ;
185
190
return None ;
186
191
}
192
+ let mut mcdc_match_branch_spans =
193
+ pattern_match_branch_records. into_values ( ) . collect :: < Vec < _ > > ( ) ;
194
+ mcdc_match_branch_spans. sort_by ( |a, b| {
195
+ if a. span . contains ( b. span ) { std:: cmp:: Ordering :: Less } else { a. span . cmp ( & b. span ) }
196
+ } ) ;
197
+ for idx in 0 ..( mcdc_match_branch_spans. len ( ) - 1 ) {
198
+ if mcdc_match_branch_spans[ idx] . span . contains ( mcdc_match_branch_spans[ idx + 1 ] . span ) {
199
+ let refined_span =
200
+ mcdc_match_branch_spans[ idx] . span . until ( mcdc_match_branch_spans[ idx + 1 ] . span ) ;
201
+ mcdc_match_branch_spans[ idx] . span = refined_span;
202
+ }
203
+ }
187
204
188
205
Some ( Box :: new ( mir:: coverage:: BranchInfo {
189
206
num_block_markers,
190
207
branch_spans,
191
208
mcdc_branch_spans,
209
+ mcdc_match_branch_spans,
192
210
mcdc_decision_spans,
193
211
} ) )
194
212
}
@@ -385,4 +403,74 @@ impl Builder<'_, '_> {
385
403
mcdc_state. record_conditions ( logical_op, span) ;
386
404
}
387
405
}
406
+
407
+ pub ( crate ) fn visit_coverage_mcdc_match_arms (
408
+ & mut self ,
409
+ test_block : BasicBlock ,
410
+ targets : impl Iterator < Item = ( Span , BasicBlock ) > ,
411
+ ) {
412
+ if !self . tcx . sess . instrument_coverage_mcdc ( ) {
413
+ return ;
414
+ }
415
+ let mut markers_map = BTreeMap :: < usize , BasicBlock > :: new ( ) ;
416
+ let mut get_marker_id = |span, block| {
417
+ self . cfg
418
+ . block_data_mut ( block)
419
+ . statements
420
+ . iter ( )
421
+ . find_map ( |statement| match statement. kind {
422
+ StatementKind :: Coverage ( CoverageKind :: BlockMarker { id } ) => Some ( id) ,
423
+ _ => None ,
424
+ } )
425
+ . unwrap_or_else ( || {
426
+ let source_info = self . source_info ( span) ;
427
+ let id = self
428
+ . coverage_branch_info
429
+ . as_mut ( )
430
+ . expect ( "Checked at entry of the function" )
431
+ . next_block_marker_id ( ) ;
432
+
433
+ let marker_statement = mir:: Statement {
434
+ source_info,
435
+ kind : mir:: StatementKind :: Coverage ( CoverageKind :: BlockMarker { id } ) ,
436
+ } ;
437
+ markers_map. insert ( id. as_usize ( ) , block) ;
438
+ self . cfg . push ( block, marker_statement) ;
439
+ id
440
+ } )
441
+ } ;
442
+ let test_block_id = get_marker_id ( Span :: default ( ) , test_block) ;
443
+
444
+ let mut targets = targets
445
+ . map ( |( span, block) | {
446
+ let marker_id = get_marker_id ( span, block) ;
447
+ ( span, marker_id)
448
+ } )
449
+ . collect :: < Vec < _ > > ( ) ;
450
+
451
+ let branch_records = self
452
+ . coverage_branch_info
453
+ . as_mut ( )
454
+ . map ( |branch_info| {
455
+ branch_info. markers_map . extend ( markers_map) ;
456
+ & mut branch_info. pattern_match_branch_records
457
+ } )
458
+ . expect ( "Checked at entry of the function" ) ;
459
+
460
+ while let Some ( ( span, matched_block) ) = targets. pop ( ) {
461
+ // By here we do not know the span of the target yet, so just record the
462
+ // basic blocks and insert BlockMarkerId later.
463
+ let record = branch_records. entry ( span) . or_insert_with ( || MCDCMatchBranchSpan {
464
+ span,
465
+ condition_info : None ,
466
+ test_markers : vec ! [ ] ,
467
+ true_markers : vec ! [ ] ,
468
+ substract_markers : vec ! [ ] ,
469
+ } ) ;
470
+ record. test_markers . push ( test_block_id) ;
471
+ record. true_markers . push ( matched_block) ;
472
+
473
+ record. substract_markers . extend ( targets. iter ( ) . map ( |( _, blk) | * blk) ) ;
474
+ }
475
+ }
388
476
}
0 commit comments