Skip to content

Commit 035b846

Browse files
committed
coverage: Split out a function for dividing coverage spans into buckets
1 parent 88ade9c commit 035b846

File tree

1 file changed

+51
-34
lines changed
  • compiler/rustc_mir_transform/src/coverage

1 file changed

+51
-34
lines changed

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_span::Span;
88
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
99
use crate::coverage::mappings;
1010
use crate::coverage::spans::from_mir::{
11-
extract_covspans_and_holes_from_mir, ExtractedCovspans, SpanFromMir,
11+
extract_covspans_and_holes_from_mir, ExtractedCovspans, Hole, SpanFromMir,
1212
};
1313
use crate::coverage::ExtractedHirInfo;
1414

@@ -53,39 +53,7 @@ pub(super) fn extract_refined_covspans(
5353
holes.sort_by(|a, b| compare_spans(a.span, b.span));
5454
holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b));
5555

56-
// Now we're ready to start carving holes out of the initial coverage spans,
57-
// and grouping them in buckets separated by the holes.
58-
59-
let mut input_covspans = VecDeque::from(covspans);
60-
let mut fragments = vec![];
61-
62-
// For each hole:
63-
// - Identify the spans that are entirely or partly before the hole.
64-
// - Put those spans in a corresponding bucket, truncated to the start of the hole.
65-
// - If one of those spans also extends after the hole, put the rest of it
66-
// in a "fragments" vector that is processed by the next hole.
67-
let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>();
68-
for (hole, bucket) in holes.iter().zip(&mut buckets) {
69-
let fragments_from_prev = std::mem::take(&mut fragments);
70-
71-
// Only inspect spans that precede or overlap this hole,
72-
// leaving the rest to be inspected by later holes.
73-
// (This relies on the spans and holes both being sorted.)
74-
let relevant_input_covspans =
75-
drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi());
76-
77-
for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) {
78-
let (before, after) = covspan.split_around_hole_span(hole.span);
79-
bucket.extend(before);
80-
fragments.extend(after);
81-
}
82-
}
83-
84-
// After finding the spans before each hole, any remaining fragments/spans
85-
// form their own final bucket, after the final hole.
86-
// (If there were no holes, this will just be all of the initial spans.)
87-
fragments.extend(input_covspans);
88-
buckets.push(fragments);
56+
let buckets = divide_spans_into_buckets(covspans, &holes);
8957

9058
for mut covspans in buckets {
9159
// Make sure each individual bucket is internally sorted.
@@ -149,6 +117,55 @@ fn split_visible_macro_spans(covspans: &mut Vec<SpanFromMir>) {
149117
covspans.extend(extra_spans);
150118
}
151119

120+
/// Uses the holes to divide the given covspans into buckets, such that:
121+
/// - No span in any hole overlaps a bucket (truncating the spans if necessary).
122+
/// - The spans in each bucket are strictly after all spans in previous buckets,
123+
/// and strictly before all spans in subsequent buckets.
124+
///
125+
/// The resulting buckets are sorted relative to each other, but might not be
126+
/// internally sorted.
127+
#[instrument(level = "debug")]
128+
fn divide_spans_into_buckets(input_covspans: Vec<Covspan>, holes: &[Hole]) -> Vec<Vec<Covspan>> {
129+
debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le()));
130+
debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le()));
131+
132+
// Now we're ready to start carving holes out of the initial coverage spans,
133+
// and grouping them in buckets separated by the holes.
134+
135+
let mut input_covspans = VecDeque::from(input_covspans);
136+
let mut fragments = vec![];
137+
138+
// For each hole:
139+
// - Identify the spans that are entirely or partly before the hole.
140+
// - Put those spans in a corresponding bucket, truncated to the start of the hole.
141+
// - If one of those spans also extends after the hole, put the rest of it
142+
// in a "fragments" vector that is processed by the next hole.
143+
let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>();
144+
for (hole, bucket) in holes.iter().zip(&mut buckets) {
145+
let fragments_from_prev = std::mem::take(&mut fragments);
146+
147+
// Only inspect spans that precede or overlap this hole,
148+
// leaving the rest to be inspected by later holes.
149+
// (This relies on the spans and holes both being sorted.)
150+
let relevant_input_covspans =
151+
drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi());
152+
153+
for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) {
154+
let (before, after) = covspan.split_around_hole_span(hole.span);
155+
bucket.extend(before);
156+
fragments.extend(after);
157+
}
158+
}
159+
160+
// After finding the spans before each hole, any remaining fragments/spans
161+
// form their own final bucket, after the final hole.
162+
// (If there were no holes, this will just be all of the initial spans.)
163+
fragments.extend(input_covspans);
164+
buckets.push(fragments);
165+
166+
buckets
167+
}
168+
152169
/// Similar to `.drain(..)`, but stops just before it would remove an item not
153170
/// satisfying the predicate.
154171
fn drain_front_while<'a, T>(

0 commit comments

Comments
 (0)