rustc_mir_transform/coverage/
mappings.rs1use rustc_index::IndexVec;
2use rustc_middle::mir::coverage::{
3 BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind, Mapping, MappingKind,
4};
5use rustc_middle::mir::{self, BasicBlock, StatementKind};
6use rustc_middle::ty::TyCtxt;
7
8use crate::coverage::graph::CoverageGraph;
9use crate::coverage::hir_info::ExtractedHirInfo;
10use crate::coverage::spans::extract_refined_covspans;
11use crate::coverage::unexpand::unexpand_into_body_span;
12
13#[derive(Default)]
14pub(crate) struct ExtractedMappings {
15 pub(crate) mappings: Vec<Mapping>,
16}
17
18pub(crate) fn extract_mappings_from_mir<'tcx>(
21 tcx: TyCtxt<'tcx>,
22 mir_body: &mir::Body<'tcx>,
23 hir_info: &ExtractedHirInfo,
24 graph: &CoverageGraph,
25) -> ExtractedMappings {
26 let mut mappings = vec![];
27
28 extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut mappings);
30
31 extract_branch_mappings(mir_body, hir_info, graph, &mut mappings);
32
33 ExtractedMappings { mappings }
34}
35
36fn resolve_block_markers(
37 coverage_info_hi: &CoverageInfoHi,
38 mir_body: &mir::Body<'_>,
39) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
40 let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
41 None,
42 coverage_info_hi.num_block_markers,
43 );
44
45 for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
47 for statement in &data.statements {
48 if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind {
49 block_markers[id] = Some(bb);
50 }
51 }
52 }
53
54 block_markers
55}
56
57pub(super) fn extract_branch_mappings(
58 mir_body: &mir::Body<'_>,
59 hir_info: &ExtractedHirInfo,
60 graph: &CoverageGraph,
61 mappings: &mut Vec<Mapping>,
62) {
63 let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
64
65 let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
66
67 mappings.extend(coverage_info_hi.branch_spans.iter().filter_map(
68 |&BranchSpan { span: raw_span, true_marker, false_marker }| try {
69 if !raw_span.ctxt().outer_expn_data().is_root() {
72 return None;
73 }
74 let span = unexpand_into_body_span(raw_span, hir_info.body_span)?;
75
76 let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
77
78 let true_bcb = bcb_from_marker(true_marker)?;
79 let false_bcb = bcb_from_marker(false_marker)?;
80
81 Mapping { span, kind: MappingKind::Branch { true_bcb, false_bcb } }
82 },
83 ));
84}