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(CoverageKind::VirtualCounter { .. }) => bug!(
105 "Unexpected coverage statement found during coverage instrumentation: {statement:?}"
106 ),
107 }
108}
109
110fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
113 match terminator.kind {
114 TerminatorKind::Unreachable
120 | TerminatorKind::Assert { .. }
121 | TerminatorKind::Drop { .. }
122 | TerminatorKind::SwitchInt { .. }
123 | TerminatorKind::FalseEdge { .. }
124 | TerminatorKind::Goto { .. } => None,
125
126 TerminatorKind::Call { ref func, .. } | TerminatorKind::TailCall { ref func, .. } => {
128 let mut span = terminator.source_info.span;
129 if let mir::Operand::Constant(constant) = func
130 && span.contains(constant.span)
131 {
132 span = constant.span;
133 }
134 Some(span)
135 }
136
137 TerminatorKind::UnwindResume
139 | TerminatorKind::UnwindTerminate(_)
140 | TerminatorKind::Return
141 | TerminatorKind::Yield { .. }
142 | TerminatorKind::CoroutineDrop
143 | TerminatorKind::FalseUnwind { .. }
144 | TerminatorKind::InlineAsm { .. } => Some(terminator.source_info.span),
145 }
146}
147
148#[derive(Debug)]
149pub(crate) struct Hole {
150 pub(crate) span: Span,
151}
152
153impl Hole {
154 pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
155 if !self.span.overlaps_or_adjacent(other.span) {
156 return false;
157 }
158
159 self.span = self.span.to(other.span);
160 true
161 }
162}
163
164#[derive(Debug)]
165pub(crate) struct SpanFromMir {
166 pub(crate) span: Span,
174 pub(crate) expn_kind: Option<ExpnKind>,
175 pub(crate) bcb: BasicCoverageBlock,
176}
177
178impl SpanFromMir {
179 pub(crate) fn for_fn_sig(fn_sig_span: Span) -> Self {
180 Self::new(fn_sig_span, None, START_BCB)
181 }
182
183 pub(crate) fn new(span: Span, expn_kind: Option<ExpnKind>, bcb: BasicCoverageBlock) -> Self {
184 Self { span, expn_kind, bcb }
185 }
186
187 pub(crate) fn into_covspan(self) -> Covspan {
188 let Self { span, expn_kind: _, bcb } = self;
189 Covspan { span, bcb }
190 }
191}