use rustc_middle::mir;
use rustc_span::Span;
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
use crate::coverage::mappings;
use crate::coverage::spans::from_mir::SpanFromMir;
use crate::coverage::ExtractedHirInfo;
mod from_mir;
pub(super) use from_mir::unexpand_into_body_span_with_visible_macro;
pub(super) fn extract_refined_covspans(
mir_body: &mir::Body<'_>,
hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
code_mappings: &mut impl Extend<mappings::CodeMapping>,
) {
let sorted_span_buckets =
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
for bucket in sorted_span_buckets {
let refined_spans = refine_sorted_spans(bucket);
code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| {
mappings::CodeMapping { span, bcb }
}));
}
}
#[derive(Debug)]
struct RefinedCovspan {
span: Span,
bcb: BasicCoverageBlock,
}
impl RefinedCovspan {
fn is_mergeable(&self, other: &Self) -> bool {
self.bcb == other.bcb
}
fn merge_from(&mut self, other: &Self) {
debug_assert!(self.is_mergeable(other));
self.span = self.span.to(other.span);
}
}
#[instrument(level = "debug")]
fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> {
let mut pending = vec![];
let mut refined = vec![];
for curr in sorted_spans {
pending.retain(|prev: &SpanFromMir| {
if prev.span.hi() <= curr.span.lo() {
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
false
} else {
prev.bcb == curr.bcb
}
});
pending.push(curr);
}
for prev in pending {
refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb });
}
debug!(?refined, "before merge");
refined.dedup_by(|b, a| {
if a.is_mergeable(b) {
debug!(?a, ?b, "merging list-adjacent refined spans");
a.merge_from(b);
true
} else {
false
}
});
debug!(?refined, "after merge");
refined
}