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;
7use rustc_span::ExpnKind;
8
9use crate::coverage::expansion::{self, ExpnTree};
10use crate::coverage::graph::CoverageGraph;
11use crate::coverage::hir_info::ExtractedHirInfo;
12use crate::coverage::spans::extract_refined_covspans;
13
14#[derive(Default)]
15pub(crate) struct ExtractedMappings {
16 pub(crate) mappings: Vec<Mapping>,
17}
18
19pub(crate) fn extract_mappings_from_mir<'tcx>(
22 tcx: TyCtxt<'tcx>,
23 mir_body: &mir::Body<'tcx>,
24 hir_info: &ExtractedHirInfo,
25 graph: &CoverageGraph,
26) -> ExtractedMappings {
27 let expn_tree = expansion::build_expn_tree(mir_body, hir_info, graph);
28
29 let mut mappings = vec![];
30
31 extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings);
33
34 extract_branch_mappings(mir_body, hir_info, graph, &expn_tree, &mut mappings);
35
36 ExtractedMappings { mappings }
37}
38
39fn resolve_block_markers(
40 coverage_info_hi: &CoverageInfoHi,
41 mir_body: &mir::Body<'_>,
42) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
43 let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
44 None,
45 coverage_info_hi.num_block_markers,
46 );
47
48 for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
50 for statement in &data.statements {
51 if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind {
52 block_markers[id] = Some(bb);
53 }
54 }
55 }
56
57 block_markers
58}
59
60fn extract_branch_mappings(
61 mir_body: &mir::Body<'_>,
62 hir_info: &ExtractedHirInfo,
63 graph: &CoverageGraph,
64 expn_tree: &ExpnTree,
65 mappings: &mut Vec<Mapping>,
66) {
67 let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
68 let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
69
70 let Some(node) = expn_tree.get(hir_info.body_span.ctxt().outer_expn()) else { return };
73 if node.expn_kind != ExpnKind::Root {
74 return;
75 }
76
77 mappings.extend(node.branch_spans.iter().filter_map(
78 |&BranchSpan { span, true_marker, false_marker }| try {
79 let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
80
81 let true_bcb = bcb_from_marker(true_marker)?;
82 let false_bcb = bcb_from_marker(false_marker)?;
83
84 Mapping { span, kind: MappingKind::Branch { true_bcb, false_bcb } }
85 },
86 ));
87}