|
1 | | -use std::collections::VecDeque; |
2 | | -use std::iter; |
3 | | - |
4 | 1 | use rustc_data_structures::fx::FxHashSet; |
5 | 2 | use rustc_middle::mir; |
6 | 3 | use rustc_middle::ty::TyCtxt; |
7 | 4 | use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; |
8 | | -use tracing::{debug, debug_span, instrument}; |
| 5 | +use tracing::instrument; |
9 | 6 |
|
10 | 7 | use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; |
11 | 8 | use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; |
@@ -83,24 +80,17 @@ pub(super) fn extract_refined_covspans<'tcx>( |
83 | 80 | holes.sort_by(|a, b| compare_spans(a.span, b.span)); |
84 | 81 | holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); |
85 | 82 |
|
86 | | - // Split the covspans into separate buckets that don't overlap any holes. |
87 | | - let buckets = divide_spans_into_buckets(covspans, &holes); |
88 | | - |
89 | | - for covspans in buckets { |
90 | | - let _span = debug_span!("processing bucket", ?covspans).entered(); |
| 83 | + // Discard any span that overlaps with a hole. |
| 84 | + discard_spans_overlapping_holes(&mut covspans, &holes); |
91 | 85 |
|
92 | | - let mut covspans = remove_unwanted_overlapping_spans(covspans); |
93 | | - debug!(?covspans, "after removing overlaps"); |
| 86 | + // Perform more refinement steps after holes have been dealt with. |
| 87 | + let mut covspans = remove_unwanted_overlapping_spans(covspans); |
| 88 | + covspans.dedup_by(|b, a| a.merge_if_eligible(b)); |
94 | 89 |
|
95 | | - // Do one last merge pass, to simplify the output. |
96 | | - covspans.dedup_by(|b, a| a.merge_if_eligible(b)); |
97 | | - debug!(?covspans, "after merge"); |
98 | | - |
99 | | - code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { |
100 | | - // Each span produced by the refiner represents an ordinary code region. |
101 | | - mappings::CodeMapping { span, bcb } |
102 | | - })); |
103 | | - } |
| 90 | + code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { |
| 91 | + // Each span produced by the refiner represents an ordinary code region. |
| 92 | + mappings::CodeMapping { span, bcb } |
| 93 | + })); |
104 | 94 | } |
105 | 95 |
|
106 | 96 | /// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate |
@@ -142,52 +132,36 @@ fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec<SpanFromMir>) |
142 | 132 | } |
143 | 133 | } |
144 | 134 |
|
145 | | -/// Uses the holes to divide the given covspans into buckets, such that: |
146 | | -/// - No span in any hole overlaps a bucket (discarding spans if necessary). |
147 | | -/// - The spans in each bucket are strictly after all spans in previous buckets, |
148 | | -/// and strictly before all spans in subsequent buckets. |
| 135 | +/// Discard all covspans that overlap a hole. |
149 | 136 | /// |
150 | | -/// The lists of covspans and holes must be sorted. |
151 | | -/// The resulting buckets are sorted relative to each other, and each bucket's |
152 | | -/// contents are sorted. |
153 | | -#[instrument(level = "debug")] |
154 | | -fn divide_spans_into_buckets(input_covspans: Vec<Covspan>, holes: &[Hole]) -> Vec<Vec<Covspan>> { |
155 | | - debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); |
| 137 | +/// The lists of covspans and holes must be sorted, and any holes that overlap |
| 138 | +/// with each other must have already been merged. |
| 139 | +fn discard_spans_overlapping_holes(covspans: &mut Vec<Covspan>, holes: &[Hole]) { |
| 140 | + debug_assert!(covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); |
156 | 141 | debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); |
| 142 | + debug_assert!(holes.array_windows().all(|[a, b]| !a.span.overlaps_or_adjacent(b.span))); |
| 143 | + |
| 144 | + let mut curr_hole = 0usize; |
| 145 | + let mut overlaps_hole = |covspan: &Covspan| -> bool { |
| 146 | + while let Some(hole) = holes.get(curr_hole) { |
| 147 | + // Both lists are sorted, so we can permanently skip any holes that |
| 148 | + // end before the start of the current span. |
| 149 | + if hole.span.hi() <= covspan.span.lo() { |
| 150 | + curr_hole += 1; |
| 151 | + continue; |
| 152 | + } |
157 | 153 |
|
158 | | - // Now we're ready to start grouping spans into buckets separated by holes. |
159 | | - |
160 | | - let mut input_covspans = VecDeque::from(input_covspans); |
161 | | - |
162 | | - // For each hole: |
163 | | - // - Identify the spans that are entirely or partly before the hole. |
164 | | - // - Discard any that overlap with the hole. |
165 | | - // - Add the remaining identified spans to the corresponding bucket. |
166 | | - let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>(); |
167 | | - for (hole, bucket) in holes.iter().zip(&mut buckets) { |
168 | | - bucket.extend( |
169 | | - drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()) |
170 | | - .filter(|c| !c.span.overlaps(hole.span)), |
171 | | - ); |
172 | | - } |
173 | | - |
174 | | - // Any remaining spans form their own final bucket, after the final hole. |
175 | | - // (If there were no holes, this will just be all of the initial spans.) |
176 | | - buckets.push(Vec::from(input_covspans)); |
| 154 | + return hole.span.overlaps(covspan.span); |
| 155 | + } |
177 | 156 |
|
178 | | - buckets |
179 | | -} |
| 157 | + // No holes left, so this covspan doesn't overlap with any holes. |
| 158 | + false |
| 159 | + }; |
180 | 160 |
|
181 | | -/// Similar to `.drain(..)`, but stops just before it would remove an item not |
182 | | -/// satisfying the predicate. |
183 | | -fn drain_front_while<'a, T>( |
184 | | - queue: &'a mut VecDeque<T>, |
185 | | - mut pred_fn: impl FnMut(&T) -> bool, |
186 | | -) -> impl Iterator<Item = T> { |
187 | | - iter::from_fn(move || queue.pop_front_if(|x| pred_fn(x))) |
| 161 | + covspans.retain(|covspan| !overlaps_hole(covspan)); |
188 | 162 | } |
189 | 163 |
|
190 | | -/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" |
| 164 | +/// Takes a list of sorted spans extracted from MIR, and "refines" |
191 | 165 | /// those spans by removing spans that overlap in unwanted ways. |
192 | 166 | #[instrument(level = "debug")] |
193 | 167 | fn remove_unwanted_overlapping_spans(sorted_spans: Vec<Covspan>) -> Vec<Covspan> { |
|
0 commit comments