| Zalathar | af33fc8 | 2024-05-02 12:30:07 +1000 | [diff] [blame] | 1 | use rustc_index::IndexVec; |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 2 | use rustc_middle::mir::coverage::{ |
| 3 | BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind, Mapping, MappingKind, |
| 4 | }; |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 5 | use rustc_middle::mir::{self, BasicBlock, StatementKind}; |
| Zalathar | abc2c70 | 2024-06-17 20:09:45 +1000 | [diff] [blame] | 6 | use rustc_middle::ty::TyCtxt; |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 7 | use rustc_span::ExpnKind; |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 8 | |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 9 | use crate::coverage::expansion::{self, ExpnTree}; |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 10 | use crate::coverage::graph::CoverageGraph; |
| Zalathar | 7671b5a | 2025-08-02 22:33:04 +1000 | [diff] [blame] | 11 | use crate::coverage::hir_info::ExtractedHirInfo; |
| Zalathar | 617de8c | 2024-06-30 17:36:16 +1000 | [diff] [blame] | 12 | use crate::coverage::spans::extract_refined_covspans; |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 13 | |
| Zalathar | 7a3e5cd | 2025-12-02 13:11:33 +1100 | [diff] [blame] | 14 | /// Indicates why mapping extraction failed, for debug-logging purposes. |
| 15 | #[derive(Debug)] |
| 16 | pub(crate) enum MappingsError { |
| 17 | NoMappings, |
| 18 | TreeSortFailure, |
| 19 | } |
| 20 | |
| Zalathar | 496ae1e | 2024-05-02 20:24:23 +1000 | [diff] [blame] | 21 | #[derive(Default)] |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 22 | pub(crate) struct ExtractedMappings { |
| 23 | pub(crate) mappings: Vec<Mapping>, |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 24 | } |
| 25 | |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 26 | /// Extracts coverage-relevant spans from MIR, and uses them to create |
| 27 | /// coverage mapping data for inclusion in MIR. |
| 28 | pub(crate) fn extract_mappings_from_mir<'tcx>( |
| Zalathar | abc2c70 | 2024-06-17 20:09:45 +1000 | [diff] [blame] | 29 | tcx: TyCtxt<'tcx>, |
| 30 | mir_body: &mir::Body<'tcx>, |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 31 | hir_info: &ExtractedHirInfo, |
| Zalathar | 544809e | 2024-12-18 13:53:23 +1100 | [diff] [blame] | 32 | graph: &CoverageGraph, |
| Zalathar | 7a3e5cd | 2025-12-02 13:11:33 +1100 | [diff] [blame] | 33 | ) -> Result<ExtractedMappings, MappingsError> { |
| 34 | let expn_tree = expansion::build_expn_tree(mir_body, hir_info, graph)?; |
| Zalathar | c783871 | 2025-11-09 18:59:28 +1100 | [diff] [blame] | 35 | |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 36 | let mut mappings = vec![]; |
| Zalathar | 496ae1e | 2024-05-02 20:24:23 +1000 | [diff] [blame] | 37 | |
| Zalathar | fb39d3e | 2025-08-02 18:28:03 +1000 | [diff] [blame] | 38 | // Extract ordinary code mappings from MIR statement/terminator spans. |
| Zalathar | c783871 | 2025-11-09 18:59:28 +1100 | [diff] [blame] | 39 | extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings); |
| Zalathar | 496ae1e | 2024-05-02 20:24:23 +1000 | [diff] [blame] | 40 | |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 41 | extract_branch_mappings(mir_body, hir_info, graph, &expn_tree, &mut mappings); |
| Zalathar | 496ae1e | 2024-05-02 20:24:23 +1000 | [diff] [blame] | 42 | |
| Zalathar | 7a3e5cd | 2025-12-02 13:11:33 +1100 | [diff] [blame] | 43 | if mappings.is_empty() { |
| 44 | tracing::debug!("no mappings were extracted"); |
| 45 | return Err(MappingsError::NoMappings); |
| 46 | } |
| 47 | Ok(ExtractedMappings { mappings }) |
| Zalathar | 1a26404 | 2024-05-02 16:28:49 +1000 | [diff] [blame] | 48 | } |
| 49 | |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 50 | fn resolve_block_markers( |
| Zalathar | f095de4 | 2024-07-04 23:52:49 +1000 | [diff] [blame] | 51 | coverage_info_hi: &CoverageInfoHi, |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 52 | mir_body: &mir::Body<'_>, |
| 53 | ) -> IndexVec<BlockMarkerId, Option<BasicBlock>> { |
| 54 | let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n( |
| 55 | None, |
| Zalathar | f095de4 | 2024-07-04 23:52:49 +1000 | [diff] [blame] | 56 | coverage_info_hi.num_block_markers, |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 57 | ); |
| 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 | |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 71 | fn extract_branch_mappings( |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 72 | mir_body: &mir::Body<'_>, |
| 73 | hir_info: &ExtractedHirInfo, |
| Zalathar | 544809e | 2024-12-18 13:53:23 +1100 | [diff] [blame] | 74 | graph: &CoverageGraph, |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 75 | expn_tree: &ExpnTree, |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 76 | mappings: &mut Vec<Mapping>, |
| 77 | ) { |
| 78 | let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; |
| Zalathar | f095de4 | 2024-07-04 23:52:49 +1000 | [diff] [blame] | 79 | let block_markers = resolve_block_markers(coverage_info_hi, mir_body); |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 80 | |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 81 | // 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 | } |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 87 | |
| Zalathar | ac43716 | 2025-11-30 15:14:47 +1100 | [diff] [blame] | 88 | mappings.extend(node.branch_spans.iter().filter_map( |
| 89 | |&BranchSpan { span, true_marker, false_marker }| try { |
| Zalathar | 544809e | 2024-12-18 13:53:23 +1100 | [diff] [blame] | 90 | let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?); |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 91 | |
| 92 | let true_bcb = bcb_from_marker(true_marker)?; |
| 93 | let false_bcb = bcb_from_marker(false_marker)?; |
| 94 | |
| Zalathar | ecce90b | 2025-08-08 21:27:29 +1000 | [diff] [blame] | 95 | Mapping { span, kind: MappingKind::Branch { true_bcb, false_bcb } } |
| 96 | }, |
| 97 | )); |
| Zalathar | ba87e5b | 2024-04-29 22:25:09 +1000 | [diff] [blame] | 98 | } |