coverage: Prepare mappings separately from injecting statements
These two tasks historically needed to be interleaved, but after various recent changes (including #116046 and #116917) they can now be fully separated.
This commit is contained in:
parent
ddca5343f2
commit
e1a2babc06
2 changed files with 44 additions and 29 deletions
|
@ -8,7 +8,7 @@ mod spans;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use self::counters::{BcbCounter, CoverageCounters};
|
use self::counters::{BcbCounter, CoverageCounters};
|
||||||
use self::graph::CoverageGraph;
|
use self::graph::{BasicCoverageBlock, CoverageGraph};
|
||||||
use self::spans::CoverageSpans;
|
use self::spans::CoverageSpans;
|
||||||
|
|
||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
|
@ -106,7 +106,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
self.coverage_counters
|
self.coverage_counters
|
||||||
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
|
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
|
||||||
|
|
||||||
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
|
let mappings = self.create_mappings(&coverage_spans);
|
||||||
|
self.inject_coverage_statements(bcb_has_coverage_spans);
|
||||||
|
|
||||||
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
||||||
function_source_hash: self.hir_info.function_source_hash,
|
function_source_hash: self.hir_info.function_source_hash,
|
||||||
|
@ -116,13 +117,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For each [`BcbCounter`] associated with a BCB node or BCB edge, create
|
/// For each coverage span extracted from MIR, create a corresponding
|
||||||
/// any corresponding mappings (for BCB nodes only), and inject any necessary
|
/// mapping.
|
||||||
/// coverage statements into MIR.
|
///
|
||||||
fn create_mappings_and_inject_coverage_statements(
|
/// Precondition: All BCBs corresponding to those spans have been given
|
||||||
&mut self,
|
/// coverage counters.
|
||||||
coverage_spans: &CoverageSpans,
|
fn create_mappings(&self, coverage_spans: &CoverageSpans) -> Vec<Mapping> {
|
||||||
) -> Vec<Mapping> {
|
|
||||||
let source_map = self.tcx.sess.source_map();
|
let source_map = self.tcx.sess.source_map();
|
||||||
let body_span = self.hir_info.body_span;
|
let body_span = self.hir_info.body_span;
|
||||||
|
|
||||||
|
@ -131,30 +131,42 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
let file_name =
|
let file_name =
|
||||||
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
|
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
|
||||||
|
|
||||||
let mut mappings = Vec::new();
|
coverage_spans
|
||||||
|
.bcbs_with_coverage_spans()
|
||||||
// Process the counters and spans associated with BCB nodes.
|
// For each BCB with spans, get a coverage term for its counter.
|
||||||
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
|
.map(|(bcb, spans)| {
|
||||||
let spans = coverage_spans.spans_for_bcb(bcb);
|
let term = self
|
||||||
let has_mappings = !spans.is_empty();
|
.coverage_counters
|
||||||
|
.bcb_counter(bcb)
|
||||||
// If this BCB has any coverage spans, add corresponding mappings to
|
.expect("all BCBs with spans were given counters")
|
||||||
// the mappings table.
|
.as_term();
|
||||||
if has_mappings {
|
(term, spans)
|
||||||
let term = counter_kind.as_term();
|
})
|
||||||
mappings.extend(spans.iter().map(|&span| {
|
// Flatten the spans into individual term/span pairs.
|
||||||
|
.flat_map(|(term, spans)| spans.iter().map(move |&span| (term, span)))
|
||||||
|
// Convert each span to a code region, and create the final mapping.
|
||||||
|
.map(|(term, span)| {
|
||||||
let code_region = make_code_region(source_map, file_name, span, body_span);
|
let code_region = make_code_region(source_map, file_name, span, body_span);
|
||||||
Mapping { code_region, term }
|
Mapping { term, code_region }
|
||||||
}));
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For each BCB node or BCB edge that has an associated coverage counter,
|
||||||
|
/// inject any necessary coverage statements into MIR.
|
||||||
|
fn inject_coverage_statements(
|
||||||
|
&mut self,
|
||||||
|
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
|
||||||
|
) {
|
||||||
|
// Process the counters associated with BCB nodes.
|
||||||
|
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
|
||||||
let do_inject = match counter_kind {
|
let do_inject = match counter_kind {
|
||||||
// Counter-increment statements always need to be injected.
|
// Counter-increment statements always need to be injected.
|
||||||
BcbCounter::Counter { .. } => true,
|
BcbCounter::Counter { .. } => true,
|
||||||
// The only purpose of expression-used statements is to detect
|
// The only purpose of expression-used statements is to detect
|
||||||
// when a mapping is unreachable, so we only inject them for
|
// when a mapping is unreachable, so we only inject them for
|
||||||
// expressions with one or more mappings.
|
// expressions with one or more mappings.
|
||||||
BcbCounter::Expression { .. } => has_mappings,
|
BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb),
|
||||||
};
|
};
|
||||||
if do_inject {
|
if do_inject {
|
||||||
inject_statement(
|
inject_statement(
|
||||||
|
@ -192,8 +204,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
// Inject a counter into the newly-created BB.
|
// Inject a counter into the newly-created BB.
|
||||||
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
|
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
mappings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
|
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
|
||||||
|
|
|
@ -48,8 +48,13 @@ impl CoverageSpans {
|
||||||
!self.bcb_to_spans[bcb].is_empty()
|
!self.bcb_to_spans[bcb].is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
|
pub(super) fn bcbs_with_coverage_spans(
|
||||||
&self.bcb_to_spans[bcb]
|
&self,
|
||||||
|
) -> impl Iterator<Item = (BasicCoverageBlock, &[Span])> {
|
||||||
|
self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| {
|
||||||
|
// Only yield BCBs that have at least one coverage span.
|
||||||
|
(!spans.is_empty()).then_some((bcb, spans.as_slice()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue