@@ -9,7 +9,7 @@ mod tests;
99
1010use self :: counters:: { CounterIncrementSite , CoverageCounters } ;
1111use self :: graph:: { BasicCoverageBlock , CoverageGraph } ;
12- use self :: spans:: { BcbBranchPair , BcbMapping , BcbMappingKind , CoverageSpans } ;
12+ use self :: spans:: { BcbBranchArm , BcbMapping , BcbMappingKind , CoverageSpans } ;
1313
1414use crate :: MirPass ;
1515
@@ -83,10 +83,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
8383 // and all `Expression` dependencies (operands) are also generated, for any other
8484 // `BasicCoverageBlock`s not already associated with a coverage span.
8585 let bcb_has_coverage_spans = |bcb| coverage_spans. bcb_has_coverage_spans ( bcb) ;
86- let coverage_counters =
86+ let mut coverage_counters =
8787 CoverageCounters :: make_bcb_counters ( & basic_coverage_blocks, bcb_has_coverage_spans) ;
8888
89- let mappings = create_mappings ( tcx, & hir_info, & coverage_spans, & coverage_counters) ;
89+ let mappings = create_mappings ( tcx, & hir_info, & coverage_spans, & mut coverage_counters) ;
9090 if mappings. is_empty ( ) {
9191 // No spans could be converted into valid mappings, so skip this function.
9292 debug ! ( "no spans could be converted into valid mappings; skipping" ) ;
@@ -120,7 +120,7 @@ fn create_mappings<'tcx>(
120120 tcx : TyCtxt < ' tcx > ,
121121 hir_info : & ExtractedHirInfo ,
122122 coverage_spans : & CoverageSpans ,
123- coverage_counters : & CoverageCounters ,
123+ coverage_counters : & mut CoverageCounters ,
124124) -> Vec < Mapping > {
125125 let source_map = tcx. sess . source_map ( ) ;
126126 let body_span = hir_info. body_span ;
@@ -169,15 +169,45 @@ fn create_mappings<'tcx>(
169169 } ,
170170 ) ) ;
171171
172- mappings. extend ( coverage_spans. branch_pairs . iter ( ) . filter_map (
173- |& BcbBranchPair { span, true_bcb, false_bcb } | {
174- let true_term = term_for_bcb ( true_bcb) ;
175- let false_term = term_for_bcb ( false_bcb) ;
176- let kind = MappingKind :: Branch { true_term, false_term } ;
177- let code_region = make_code_region ( source_map, file_name, span, body_span) ?;
178- Some ( Mapping { kind, code_region } )
179- } ,
180- ) ) ;
172+ for arm_list in & coverage_spans. branch_arm_lists {
173+ let mut arms_rev = arm_list. iter ( ) . rev ( ) ;
174+
175+ let mut rest_counter = {
176+ // The last arm's span is ignored, because its BCB is only used as the
177+ // false branch of the second-last arm; it's not a branch of its own.
178+ let Some ( & BcbBranchArm { span : _, pre_guard_bcb, arm_taken_bcb } ) = arms_rev. next ( )
179+ else {
180+ continue ;
181+ } ;
182+ debug_assert_eq ! ( pre_guard_bcb, arm_taken_bcb, "last arm should not have a guard" ) ;
183+ coverage_counters. bcb_counter ( pre_guard_bcb) . expect ( "all relevant BCBs have counters" )
184+ } ;
185+
186+ // All relevant BCBs should have counters, so we can `.unwrap()` them.
187+ for & BcbBranchArm { span, pre_guard_bcb, arm_taken_bcb } in arms_rev {
188+ // Number of times the pattern matched.
189+ let matched_counter = coverage_counters. bcb_counter ( pre_guard_bcb) . unwrap ( ) ;
190+ // Number of times the pattern matched and the guard succeeded.
191+ let arm_taken_counter = coverage_counters. bcb_counter ( arm_taken_bcb) . unwrap ( ) ;
192+ // Total number of times execution logically reached this pattern.
193+ let reached_counter =
194+ coverage_counters. make_expression ( rest_counter, Op :: Add , arm_taken_counter) ;
195+ // Number of times execution reached this pattern, but didn't match it.
196+ let unmatched_counter =
197+ coverage_counters. make_expression ( reached_counter, Op :: Subtract , matched_counter) ;
198+
199+ let kind = MappingKind :: Branch {
200+ true_term : matched_counter. as_term ( ) ,
201+ false_term : unmatched_counter. as_term ( ) ,
202+ } ;
203+
204+ if let Some ( code_region) = make_code_region ( source_map, file_name, span, body_span) {
205+ mappings. push ( Mapping { kind, code_region } ) ;
206+ }
207+
208+ rest_counter = reached_counter;
209+ }
210+ }
181211
182212 mappings
183213}
0 commit comments