rustc_mir_transform/coverage/spans/
from_mir.rs1use std::iter;
2
3use rustc_middle::bug;
4use rustc_middle::mir::coverage::CoverageKind;
5use rustc_middle::mir::{
6 self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind,
7};
8use rustc_span::{ExpnKind, Span};
9
10use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
11use crate::coverage::spans::Covspan;
12
13#[derive(Debug)]
14pub(crate) struct RawSpanFromMir {
15 pub(crate) raw_span: Span,
19 pub(crate) bcb: BasicCoverageBlock,
20}
21
22pub(crate) fn extract_raw_spans_from_mir<'tcx>(
30 mir_body: &mir::Body<'tcx>,
31 graph: &CoverageGraph,
32) -> Vec<RawSpanFromMir> {
33 let mut raw_spans = vec![];
34
35 for (bcb, bcb_data) in graph.iter_enumerated() {
37 let make_raw_span = |raw_span: Span| RawSpanFromMir { raw_span, bcb };
38
39 for &bb in &bcb_data.basic_blocks {
41 let bb_data = &mir_body[bb];
42
43 let statements = bb_data.statements.iter();
44 raw_spans.extend(statements.filter_map(filtered_statement_span).map(make_raw_span));
45
46 let terminator = iter::once(bb_data.terminator());
49 raw_spans.extend(terminator.filter_map(filtered_terminator_span).map(make_raw_span));
50 }
51 }
52
53 raw_spans
54}
55
56fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
59 match statement.kind {
60 StatementKind::StorageLive(_)
63 | StatementKind::StorageDead(_)
64 | StatementKind::ConstEvalCounter
65 | StatementKind::BackwardIncompatibleDropHint { .. }
66 | StatementKind::Nop => None,
67
68 StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None,
85
86 StatementKind::FakeRead(_)
88 | StatementKind::Intrinsic(..)
89 | StatementKind::Coverage(
90 CoverageKind::SpanMarker,
92 )
93 | StatementKind::Assign(_)
94 | StatementKind::SetDiscriminant { .. }
95 | StatementKind::Deinit(..)
96 | StatementKind::Retag(_, _)
97 | StatementKind::PlaceMention(..)
98 | StatementKind::AscribeUserType(_, _) => Some(statement.source_info.span),
99
100 StatementKind::Coverage(CoverageKind::BlockMarker { .. }) => None,
102
103 StatementKind::Coverage(
105 CoverageKind::VirtualCounter { .. }
106 | CoverageKind::CondBitmapUpdate { .. }
107 | CoverageKind::TestVectorBitmapUpdate { .. },
108 ) => bug!(
109 "Unexpected coverage statement found during coverage instrumentation: {statement:?}"
110 ),
111 }
112}
113
114fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
117 match terminator.kind {
118 TerminatorKind::Unreachable
124 | TerminatorKind::Assert { .. }
125 | TerminatorKind::Drop { .. }
126 | TerminatorKind::SwitchInt { .. }
127 | TerminatorKind::FalseEdge { .. }
128 | TerminatorKind::Goto { .. } => None,
129
130 TerminatorKind::Call { ref func, .. } | TerminatorKind::TailCall { ref func, .. } => {
132 let mut span = terminator.source_info.span;
133 if let mir::Operand::Constant(constant) = func
134 && span.contains(constant.span)
135 {
136 span = constant.span;
137 }
138 Some(span)
139 }
140
141 TerminatorKind::UnwindResume
143 | TerminatorKind::UnwindTerminate(_)
144 | TerminatorKind::Return
145 | TerminatorKind::Yield { .. }
146 | TerminatorKind::CoroutineDrop
147 | TerminatorKind::FalseUnwind { .. }
148 | TerminatorKind::InlineAsm { .. } => Some(terminator.source_info.span),
149 }
150}
151
152#[derive(Debug)]
153pub(crate) struct Hole {
154 pub(crate) span: Span,
155}
156
157impl Hole {
158 pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
159 if !self.span.overlaps_or_adjacent(other.span) {
160 return false;
161 }
162
163 self.span = self.span.to(other.span);
164 true
165 }
166}
167
168#[derive(Debug)]
169pub(crate) struct SpanFromMir {
170 pub(crate) span: Span,
178 pub(crate) expn_kind: Option<ExpnKind>,
179 pub(crate) bcb: BasicCoverageBlock,
180}
181
182impl SpanFromMir {
183 pub(crate) fn for_fn_sig(fn_sig_span: Span) -> Self {
184 Self::new(fn_sig_span, None, START_BCB)
185 }
186
187 pub(crate) fn new(span: Span, expn_kind: Option<ExpnKind>, bcb: BasicCoverageBlock) -> Self {
188 Self { span, expn_kind, bcb }
189 }
190
191 pub(crate) fn into_covspan(self) -> Covspan {
192 let Self { span, expn_kind: _, bcb } = self;
193 Covspan { span, bcb }
194 }
195}