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