blob: 4581afa99a31bf41f576392cfda854a78eab0391 [file] [log] [blame]
Zalatharaf33fc82024-05-02 12:30:07 +10001use rustc_index::IndexVec;
Zalatharecce90b2025-08-08 21:27:29 +10002use rustc_middle::mir::coverage::{
3 BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind, Mapping, MappingKind,
4};
Zalatharba87e5b2024-04-29 22:25:09 +10005use rustc_middle::mir::{self, BasicBlock, StatementKind};
Zalatharabc2c702024-06-17 20:09:45 +10006use rustc_middle::ty::TyCtxt;
Zalatharac437162025-11-30 15:14:47 +11007use rustc_span::ExpnKind;
Zalatharba87e5b2024-04-29 22:25:09 +10008
Zalatharac437162025-11-30 15:14:47 +11009use crate::coverage::expansion::{self, ExpnTree};
Zalatharecce90b2025-08-08 21:27:29 +100010use crate::coverage::graph::CoverageGraph;
Zalathar7671b5a2025-08-02 22:33:04 +100011use crate::coverage::hir_info::ExtractedHirInfo;
Zalathar617de8c2024-06-30 17:36:16 +100012use crate::coverage::spans::extract_refined_covspans;
Zalatharba87e5b2024-04-29 22:25:09 +100013
Zalathar7a3e5cd2025-12-02 13:11:33 +110014/// Indicates why mapping extraction failed, for debug-logging purposes.
15#[derive(Debug)]
16pub(crate) enum MappingsError {
17 NoMappings,
18 TreeSortFailure,
19}
20
Zalathar496ae1e2024-05-02 20:24:23 +100021#[derive(Default)]
Zalatharecce90b2025-08-08 21:27:29 +100022pub(crate) struct ExtractedMappings {
23 pub(crate) mappings: Vec<Mapping>,
Zalatharba87e5b2024-04-29 22:25:09 +100024}
25
Zalatharecce90b2025-08-08 21:27:29 +100026/// Extracts coverage-relevant spans from MIR, and uses them to create
27/// coverage mapping data for inclusion in MIR.
28pub(crate) fn extract_mappings_from_mir<'tcx>(
Zalatharabc2c702024-06-17 20:09:45 +100029 tcx: TyCtxt<'tcx>,
30 mir_body: &mir::Body<'tcx>,
Zalatharba87e5b2024-04-29 22:25:09 +100031 hir_info: &ExtractedHirInfo,
Zalathar544809e2024-12-18 13:53:23 +110032 graph: &CoverageGraph,
Zalathar7a3e5cd2025-12-02 13:11:33 +110033) -> Result<ExtractedMappings, MappingsError> {
34 let expn_tree = expansion::build_expn_tree(mir_body, hir_info, graph)?;
Zalatharc7838712025-11-09 18:59:28 +110035
Zalatharecce90b2025-08-08 21:27:29 +100036 let mut mappings = vec![];
Zalathar496ae1e2024-05-02 20:24:23 +100037
Zalatharfb39d3e2025-08-02 18:28:03 +100038 // Extract ordinary code mappings from MIR statement/terminator spans.
Zalatharc7838712025-11-09 18:59:28 +110039 extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings);
Zalathar496ae1e2024-05-02 20:24:23 +100040
Zalatharac437162025-11-30 15:14:47 +110041 extract_branch_mappings(mir_body, hir_info, graph, &expn_tree, &mut mappings);
Zalathar496ae1e2024-05-02 20:24:23 +100042
Zalathar7a3e5cd2025-12-02 13:11:33 +110043 if mappings.is_empty() {
44 tracing::debug!("no mappings were extracted");
45 return Err(MappingsError::NoMappings);
46 }
47 Ok(ExtractedMappings { mappings })
Zalathar1a264042024-05-02 16:28:49 +100048}
49
Zalatharba87e5b2024-04-29 22:25:09 +100050fn resolve_block_markers(
Zalatharf095de42024-07-04 23:52:49 +100051 coverage_info_hi: &CoverageInfoHi,
Zalatharba87e5b2024-04-29 22:25:09 +100052 mir_body: &mir::Body<'_>,
53) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
54 let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
55 None,
Zalatharf095de42024-07-04 23:52:49 +100056 coverage_info_hi.num_block_markers,
Zalatharba87e5b2024-04-29 22:25:09 +100057 );
58
59 // Fill out the mapping from block marker IDs to their enclosing blocks.
60 for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
61 for statement in &data.statements {
62 if let StatementKind::Coverage(CoverageKind::BlockMarker { id }) = statement.kind {
63 block_markers[id] = Some(bb);
64 }
65 }
66 }
67
68 block_markers
69}
70
Zalatharac437162025-11-30 15:14:47 +110071fn extract_branch_mappings(
Zalatharba87e5b2024-04-29 22:25:09 +100072 mir_body: &mir::Body<'_>,
73 hir_info: &ExtractedHirInfo,
Zalathar544809e2024-12-18 13:53:23 +110074 graph: &CoverageGraph,
Zalatharac437162025-11-30 15:14:47 +110075 expn_tree: &ExpnTree,
Zalatharecce90b2025-08-08 21:27:29 +100076 mappings: &mut Vec<Mapping>,
77) {
78 let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
Zalatharf095de42024-07-04 23:52:49 +100079 let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
Zalatharba87e5b2024-04-29 22:25:09 +100080
Zalatharac437162025-11-30 15:14:47 +110081 // For now, ignore any branch span that was introduced by
82 // expansion. This makes things like assert macros less noisy.
83 let Some(node) = expn_tree.get(hir_info.body_span.ctxt().outer_expn()) else { return };
84 if node.expn_kind != ExpnKind::Root {
85 return;
86 }
Zalatharba87e5b2024-04-29 22:25:09 +100087
Zalatharac437162025-11-30 15:14:47 +110088 mappings.extend(node.branch_spans.iter().filter_map(
89 |&BranchSpan { span, true_marker, false_marker }| try {
Zalathar544809e2024-12-18 13:53:23 +110090 let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
Zalatharba87e5b2024-04-29 22:25:09 +100091
92 let true_bcb = bcb_from_marker(true_marker)?;
93 let false_bcb = bcb_from_marker(false_marker)?;
94
Zalatharecce90b2025-08-08 21:27:29 +100095 Mapping { span, kind: MappingKind::Branch { true_bcb, false_bcb } }
96 },
97 ));
Zalatharba87e5b2024-04-29 22:25:09 +100098}