Skip to content

Commit 118f66c

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

File tree

1 file changed

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

1 file changed

+52
-34
lines changed

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 52 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,8 @@ 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+
// Split the covspans into separate buckets that don't overlap any holes.
57+
let buckets = divide_spans_into_buckets(covspans, &holes);
8958

9059
for mut covspans in buckets {
9160
// Make sure each individual bucket is internally sorted.
@@ -149,6 +118,55 @@ fn split_visible_macro_spans(covspans: &mut Vec<SpanFromMir>) {
149118
covspans.extend(extra_spans);
150119
}
151120

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

0 commit comments

Comments
 (0)