|
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