1 use super::debug
::term_type
;
2 use super::graph
::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}
;
4 use itertools
::Itertools
;
5 use rustc_data_structures
::graph
::WithNumNodes
;
6 use rustc_middle
::mir
::spanview
::source_range_no_file
;
7 use rustc_middle
::mir
::{
8 self, AggregateKind
, BasicBlock
, FakeReadCause
, Rvalue
, Statement
, StatementKind
, Terminator
,
11 use rustc_middle
::ty
::TyCtxt
;
12 use rustc_span
::source_map
::original_sp
;
13 use rustc_span
::{BytePos, ExpnKind, MacroKind, Span, Symbol}
;
15 use std
::cell
::RefCell
;
16 use std
::cmp
::Ordering
;
18 #[derive(Debug, Copy, Clone)]
19 pub(super) enum CoverageStatement
{
20 Statement(BasicBlock
, Span
, usize),
21 Terminator(BasicBlock
, Span
),
24 impl CoverageStatement
{
25 pub fn format
<'tcx
>(&self, tcx
: TyCtxt
<'tcx
>, mir_body
: &mir
::Body
<'tcx
>) -> String
{
27 Self::Statement(bb
, span
, stmt_index
) => {
28 let stmt
= &mir_body
[bb
].statements
[stmt_index
];
31 source_range_no_file(tcx
, span
),
37 Self::Terminator(bb
, span
) => {
38 let term
= mir_body
[bb
].terminator();
41 source_range_no_file(tcx
, span
),
43 term_type(&term
.kind
),
50 pub fn span(&self) -> Span
{
52 Self::Statement(_
, span
, _
) | Self::Terminator(_
, span
) => *span
,
57 /// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
58 /// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
59 /// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
60 /// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the
61 /// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s.
63 /// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that
64 /// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches
65 /// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
66 /// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`.
67 #[derive(Debug, Clone)]
68 pub(super) struct CoverageSpan
{
71 pub current_macro_or_none
: RefCell
<Option
<Option
<Symbol
>>>,
72 pub bcb
: BasicCoverageBlock
,
73 pub coverage_statements
: Vec
<CoverageStatement
>,
78 pub fn for_fn_sig(fn_sig_span
: Span
) -> Self {
81 expn_span
: fn_sig_span
,
82 current_macro_or_none
: Default
::default(),
84 coverage_statements
: vec
![],
90 statement
: &Statement
<'_
>,
93 bcb
: BasicCoverageBlock
,
97 let is_closure
= match statement
.kind
{
98 StatementKind
::Assign(box (_
, Rvalue
::Aggregate(box ref kind
, _
))) => {
99 matches
!(kind
, AggregateKind
::Closure(_
, _
) | AggregateKind
::Generator(_
, _
, _
))
107 current_macro_or_none
: Default
::default(),
109 coverage_statements
: vec
![CoverageStatement
::Statement(bb
, span
, stmt_index
)],
114 pub fn for_terminator(
117 bcb
: BasicCoverageBlock
,
123 current_macro_or_none
: Default
::default(),
125 coverage_statements
: vec
![CoverageStatement
::Terminator(bb
, span
)],
130 pub fn merge_from(&mut self, mut other
: CoverageSpan
) {
131 debug_assert
!(self.is_mergeable(&other
));
132 self.span
= self.span
.to(other
.span
);
133 self.coverage_statements
.append(&mut other
.coverage_statements
);
136 pub fn cutoff_statements_at(&mut self, cutoff_pos
: BytePos
) {
137 self.coverage_statements
.retain(|covstmt
| covstmt
.span().hi() <= cutoff_pos
);
138 if let Some(highest_covstmt
) =
139 self.coverage_statements
.iter().max_by_key(|covstmt
| covstmt
.span().hi())
141 self.span
= self.span
.with_hi(highest_covstmt
.span().hi());
146 pub fn is_mergeable(&self, other
: &Self) -> bool
{
147 self.is_in_same_bcb(other
) && !(self.is_closure
|| other
.is_closure
)
151 pub fn is_in_same_bcb(&self, other
: &Self) -> bool
{
152 self.bcb
== other
.bcb
155 pub fn format
<'tcx
>(&self, tcx
: TyCtxt
<'tcx
>, mir_body
: &mir
::Body
<'tcx
>) -> String
{
158 source_range_no_file(tcx
, self.span
),
159 self.format_coverage_statements(tcx
, mir_body
).replace('
\n'
, "\n "),
163 pub fn format_coverage_statements
<'tcx
>(
166 mir_body
: &mir
::Body
<'tcx
>,
168 let mut sorted_coverage_statements
= self.coverage_statements
.clone();
169 sorted_coverage_statements
.sort_unstable_by_key(|covstmt
| match *covstmt
{
170 CoverageStatement
::Statement(bb
, _
, index
) => (bb
, index
),
171 CoverageStatement
::Terminator(bb
, _
) => (bb
, usize::MAX
),
173 sorted_coverage_statements
.iter().map(|covstmt
| covstmt
.format(tcx
, mir_body
)).join("\n")
176 /// If the span is part of a macro, returns the macro name symbol.
177 pub fn current_macro(&self) -> Option
<Symbol
> {
178 self.current_macro_or_none
180 .get_or_insert_with(|| {
181 if let ExpnKind
::Macro(MacroKind
::Bang
, current_macro
) =
182 self.expn_span
.ctxt().outer_expn_data().kind
184 return Some(current_macro
);
188 .map(|symbol
| symbol
)
191 /// If the span is part of a macro, and the macro is visible (expands directly to the given
192 /// body_span), returns the macro name symbol.
193 pub fn visible_macro(&self, body_span
: Span
) -> Option
<Symbol
> {
194 if let Some(current_macro
) = self.current_macro() && self
197 .unwrap_or_else(|| bug
!("macro must have a parent"))
200 return Some(current_macro
);
205 pub fn is_macro_expansion(&self) -> bool
{
206 self.current_macro().is_some()
210 /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a
211 /// minimal set of `CoverageSpan`s, using the BCB CFG to determine where it is safe and useful to:
213 /// * Remove duplicate source code coverage regions
214 /// * Merge spans that represent continuous (both in source code and control flow), non-branching
216 /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
217 pub struct CoverageSpans
<'a
, 'tcx
> {
218 /// The MIR, used to look up `BasicBlockData`.
219 mir_body
: &'a mir
::Body
<'tcx
>,
221 /// A `Span` covering the signature of function for the MIR.
224 /// A `Span` covering the function body of the MIR (typically from left curly brace to right
228 /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
229 basic_coverage_blocks
: &'a CoverageGraph
,
231 /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative
232 /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
233 sorted_spans_iter
: Option
<std
::vec
::IntoIter
<CoverageSpan
>>,
235 /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the
236 /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to
237 /// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next
239 some_curr
: Option
<CoverageSpan
>,
241 /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span`
242 /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()`
244 curr_original_span
: Span
,
246 /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
247 /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
248 some_prev
: Option
<CoverageSpan
>,
250 /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span`
251 /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()`
253 prev_original_span
: Span
,
255 /// A copy of the expn_span from the prior iteration.
256 prev_expn_span
: Option
<Span
>,
258 /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
259 /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
260 /// If a new `curr` span also fits this criteria (compared to an existing list of
261 /// `pending_dups`), that `curr` `CoverageSpan` moves to `prev` before possibly being added to
262 /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups`
263 /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev`
264 /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a
265 /// `prev` with a matching `Span`)
266 pending_dups
: Vec
<CoverageSpan
>,
268 /// The final `CoverageSpan`s to add to the coverage map. A `Counter` or `Expression`
269 /// will also be injected into the MIR for each `CoverageSpan`.
270 refined_spans
: Vec
<CoverageSpan
>,
273 impl<'a
, 'tcx
> CoverageSpans
<'a
, 'tcx
> {
274 /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
277 /// The basic steps are:
279 /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
280 /// `BasicCoverageBlockData`.
281 /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
282 /// are sorted with longer spans before shorter spans; and equal spans are sorted
283 /// (deterministically) based on "dominator" relationship (if any).
284 /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
285 /// if another span or spans are already counting the same code region), or should be merged
286 /// into a broader combined span (because it represents a contiguous, non-branching, and
287 /// uninterrupted region of source code).
289 /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
290 /// closures have their own MIR, their `Span` in their enclosing function should be left
293 /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
295 pub(super) fn generate_coverage_spans(
296 mir_body
: &'a mir
::Body
<'tcx
>,
297 fn_sig_span
: Span
, // Ensured to be same SourceFile and SyntaxContext as `body_span`
299 basic_coverage_blocks
: &'a CoverageGraph
,
300 ) -> Vec
<CoverageSpan
> {
301 let mut coverage_spans
= CoverageSpans
{
305 basic_coverage_blocks
,
306 sorted_spans_iter
: None
,
307 refined_spans
: Vec
::with_capacity(basic_coverage_blocks
.num_nodes() * 2),
309 curr_original_span
: Span
::with_root_ctxt(BytePos(0), BytePos(0)),
311 prev_original_span
: Span
::with_root_ctxt(BytePos(0), BytePos(0)),
312 prev_expn_span
: None
,
313 pending_dups
: Vec
::new(),
316 let sorted_spans
= coverage_spans
.mir_to_initial_sorted_coverage_spans();
318 coverage_spans
.sorted_spans_iter
= Some(sorted_spans
.into_iter());
320 coverage_spans
.to_refined_spans()
323 fn mir_to_initial_sorted_coverage_spans(&self) -> Vec
<CoverageSpan
> {
324 let mut initial_spans
= Vec
::<CoverageSpan
>::with_capacity(self.mir_body
.num_nodes() * 2);
325 for (bcb
, bcb_data
) in self.basic_coverage_blocks
.iter_enumerated() {
326 initial_spans
.extend(self.bcb_to_initial_coverage_spans(bcb
, bcb_data
));
329 if initial_spans
.is_empty() {
330 // This can happen if, for example, the function is unreachable (contains only a
331 // `BasicBlock`(s) with an `Unreachable` terminator).
332 return initial_spans
;
335 initial_spans
.push(CoverageSpan
::for_fn_sig(self.fn_sig_span
));
337 initial_spans
.sort_unstable_by(|a
, b
| {
338 if a
.span
.lo() == b
.span
.lo() {
339 if a
.span
.hi() == b
.span
.hi() {
340 if a
.is_in_same_bcb(b
) {
341 Some(Ordering
::Equal
)
343 // Sort equal spans by dominator relationship, in reverse order (so
344 // dominators always come after the dominated equal spans). When later
345 // comparing two spans in order, the first will either dominate the second,
346 // or they will have no dominator relationship.
347 self.basic_coverage_blocks
.dominators().rank_partial_cmp(b
.bcb
, a
.bcb
)
350 // Sort hi() in reverse order so shorter spans are attempted after longer spans.
351 // This guarantees that, if a `prev` span overlaps, and is not equal to, a
352 // `curr` span, the prev span either extends further left of the curr span, or
353 // they start at the same position and the prev span extends further right of
354 // the end of the curr span.
355 b
.span
.hi().partial_cmp(&a
.span
.hi())
358 a
.span
.lo().partial_cmp(&b
.span
.lo())
366 /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
367 /// de-duplicated `CoverageSpan`s.
368 fn to_refined_spans(mut self) -> Vec
<CoverageSpan
> {
369 while self.next_coverage_span() {
370 if self.some_prev
.is_none() {
371 debug
!(" initial span");
372 self.check_invoked_macro_name_span();
373 } else if self.curr().is_mergeable(self.prev()) {
374 debug
!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev());
375 let prev
= self.take_prev();
376 self.curr_mut().merge_from(prev
);
377 self.check_invoked_macro_name_span();
378 // Note that curr.span may now differ from curr_original_span
379 } else if self.prev_ends_before_curr() {
381 " different bcbs and disjoint spans, so keep curr for next iter, and add \
385 let prev
= self.take_prev();
386 self.push_refined_span(prev
);
387 self.check_invoked_macro_name_span();
388 } else if self.prev().is_closure
{
389 // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
392 " curr overlaps a closure (prev). Drop curr and keep prev for next iter. \
397 } else if self.curr().is_closure
{
398 self.carve_out_span_for_closure();
399 } else if self.prev_original_span
== self.curr().span
{
400 // Note that this compares the new (`curr`) span to `prev_original_span`.
401 // In this branch, the actual span byte range of `prev_original_span` is not
402 // important. What is important is knowing whether the new `curr` span was
403 // **originally** the same as the original span of `prev()`. The original spans
404 // reflect their original sort order, and for equal spans, conveys a partial
405 // ordering based on CFG dominator priority.
406 if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
407 // Macros that expand to include branching (such as
408 // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
409 // `trace!()) typically generate callee spans with identical
410 // ranges (typically the full span of the macro) for all
411 // `BasicBlocks`. This makes it impossible to distinguish
412 // the condition (`if val1 != val2`) from the optional
413 // branched statements (such as the call to `panic!()` on
414 // assert failure). In this case it is better (or less
415 // worse) to drop the optional branch bcbs and keep the
416 // non-conditional statements, to count when reached.
418 " curr and prev are part of a macro expansion, and curr has the same span \
419 as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
425 self.hold_pending_dups_unless_dominated();
428 self.cutoff_prev_at_overlapping_curr();
429 self.check_invoked_macro_name_span();
433 debug
!(" AT END, adding last prev={:?}", self.prev());
434 let prev
= self.take_prev();
435 let pending_dups
= self.pending_dups
.split_off(0);
436 for dup
in pending_dups
{
437 debug
!(" ...adding at least one pending dup={:?}", dup
);
438 self.push_refined_span(dup
);
441 // Async functions wrap a closure that implements the body to be executed. The enclosing
442 // function is called and returns an `impl Future` without initially executing any of the
443 // body. To avoid showing the return from the enclosing function as a "covered" return from
444 // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is
445 // excluded. The closure's `Return` is the only one that will be counted. This provides
446 // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
447 // of the function body.)
448 let body_ends_with_closure
= if let Some(last_covspan
) = self.refined_spans
.last() {
449 last_covspan
.is_closure
&& last_covspan
.span
.hi() == self.body_span
.hi()
454 if !body_ends_with_closure
{
455 self.push_refined_span(prev
);
458 // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
459 // regions for the current function leave room for the closure's own coverage regions
460 // (injected separately, from the closure's own MIR).
461 self.refined_spans
.retain(|covspan
| !covspan
.is_closure
);
465 fn push_refined_span(&mut self, covspan
: CoverageSpan
) {
466 let len
= self.refined_spans
.len();
468 let last
= &mut self.refined_spans
[len
- 1];
469 if last
.is_mergeable(&covspan
) {
471 "merging new refined span with last refined span, last={:?}, covspan={:?}",
474 last
.merge_from(covspan
);
478 self.refined_spans
.push(covspan
)
481 fn check_invoked_macro_name_span(&mut self) {
482 if let Some(visible_macro
) = self.curr().visible_macro(self.body_span
) {
483 if self.prev_expn_span
.map_or(true, |prev_expn_span
| {
484 self.curr().expn_span
.ctxt() != prev_expn_span
.ctxt()
486 let merged_prefix_len
= self.curr_original_span
.lo() - self.curr().span
.lo();
487 let after_macro_bang
=
488 merged_prefix_len
+ BytePos(visible_macro
.as_str().len() as u32 + 1);
489 let mut macro_name_cov
= self.curr().clone();
490 self.curr_mut().span
=
491 self.curr().span
.with_lo(self.curr().span
.lo() + after_macro_bang
);
492 macro_name_cov
.span
=
493 macro_name_cov
.span
.with_hi(macro_name_cov
.span
.lo() + after_macro_bang
);
495 " and curr starts a new macro expansion, so add a new span just for \
496 the macro `{}!`, new span={:?}",
497 visible_macro
, macro_name_cov
499 self.push_refined_span(macro_name_cov
);
504 // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
505 // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
506 // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
507 // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
508 // `Statement`s and/or `Terminator`s.)
509 fn bcb_to_initial_coverage_spans(
511 bcb
: BasicCoverageBlock
,
512 bcb_data
: &'a BasicCoverageBlockData
,
513 ) -> Vec
<CoverageSpan
> {
518 let data
= &self.mir_body
[bb
];
522 .filter_map(move |(index
, statement
)| {
523 filtered_statement_span(statement
).map(|span
| {
524 CoverageSpan
::for_statement(
526 function_source_span(span
, self.body_span
),
534 .chain(filtered_terminator_span(data
.terminator()).map(|span
| {
535 CoverageSpan
::for_terminator(
536 function_source_span(span
, self.body_span
),
546 fn curr(&self) -> &CoverageSpan
{
549 .unwrap_or_else(|| bug
!("invalid attempt to unwrap a None some_curr"))
552 fn curr_mut(&mut self) -> &mut CoverageSpan
{
555 .unwrap_or_else(|| bug
!("invalid attempt to unwrap a None some_curr"))
558 fn prev(&self) -> &CoverageSpan
{
561 .unwrap_or_else(|| bug
!("invalid attempt to unwrap a None some_prev"))
564 fn prev_mut(&mut self) -> &mut CoverageSpan
{
567 .unwrap_or_else(|| bug
!("invalid attempt to unwrap a None some_prev"))
570 fn take_prev(&mut self) -> CoverageSpan
{
571 self.some_prev
.take().unwrap_or_else(|| bug
!("invalid attempt to unwrap a None some_prev"))
574 /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
575 /// `pending_dups` spans), then one of the following two things happened during the previous
577 /// * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups
578 /// (in which case there should be at least two spans in `pending_dups`); or
579 /// * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case
580 /// `pending_dups` could have as few as one span)
581 /// In either case, no more spans will match the span of `pending_dups`, so
582 /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
583 fn check_pending_dups(&mut self) {
584 if let Some(dup
) = self.pending_dups
.last() && dup
.span
!= self.prev().span
{
586 " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
587 previous iteration, or prev started a new disjoint span"
589 if dup
.span
.hi() <= self.curr().span
.lo() {
590 let pending_dups
= self.pending_dups
.split_off(0);
591 for dup
in pending_dups
.into_iter() {
592 debug
!(" ...adding at least one pending={:?}", dup
);
593 self.push_refined_span(dup
);
596 self.pending_dups
.clear();
601 /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
602 fn next_coverage_span(&mut self) -> bool
{
603 if let Some(curr
) = self.some_curr
.take() {
604 self.prev_expn_span
= Some(curr
.expn_span
);
605 self.some_prev
= Some(curr
);
606 self.prev_original_span
= self.curr_original_span
;
608 while let Some(curr
) = self.sorted_spans_iter
.as_mut().unwrap().next() {
609 debug
!("FOR curr={:?}", curr
);
610 if self.some_prev
.is_some() && self.prev_starts_after_next(&curr
) {
612 " prev.span starts after curr.span, so curr will be dropped (skipping past \
613 closure?); prev={:?}",
617 // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
618 // by `self.curr_mut().merge_from(prev)`.
619 self.curr_original_span
= curr
.span
;
620 self.some_curr
.replace(curr
);
621 self.check_pending_dups();
628 /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
629 /// `curr` coverage span.
630 fn take_curr(&mut self) -> CoverageSpan
{
631 self.some_curr
.take().unwrap_or_else(|| bug
!("invalid attempt to unwrap a None some_curr"))
634 /// Returns true if the curr span should be skipped because prev has already advanced beyond the
635 /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
636 /// of code, such as skipping past a closure.
637 fn prev_starts_after_next(&self, next_curr
: &CoverageSpan
) -> bool
{
638 self.prev().span
.lo() > next_curr
.span
.lo()
641 /// Returns true if the curr span starts past the end of the prev span, which means they don't
642 /// overlap, so we now know the prev can be added to the refined coverage spans.
643 fn prev_ends_before_curr(&self) -> bool
{
644 self.prev().span
.hi() <= self.curr().span
.lo()
647 /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
648 /// `prev`'s span. (The closure's coverage counters will be injected when processing the
649 /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
650 /// extends to the right of the closure, update `prev` to that portion of the span. For any
651 /// `pending_dups`, repeat the same process.
652 fn carve_out_span_for_closure(&mut self) {
653 let curr_span
= self.curr().span
;
654 let left_cutoff
= curr_span
.lo();
655 let right_cutoff
= curr_span
.hi();
656 let has_pre_closure_span
= self.prev().span
.lo() < right_cutoff
;
657 let has_post_closure_span
= self.prev().span
.hi() > right_cutoff
;
658 let mut pending_dups
= self.pending_dups
.split_off(0);
659 if has_pre_closure_span
{
660 let mut pre_closure
= self.prev().clone();
661 pre_closure
.span
= pre_closure
.span
.with_hi(left_cutoff
);
662 debug
!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure
);
663 if !pending_dups
.is_empty() {
664 for mut dup
in pending_dups
.iter().cloned() {
665 dup
.span
= dup
.span
.with_hi(left_cutoff
);
666 debug
!(" ...and at least one pre_closure dup={:?}", dup
);
667 self.push_refined_span(dup
);
670 self.push_refined_span(pre_closure
);
672 if has_post_closure_span
{
673 // Mutate `prev.span()` to start after the closure (and discard curr).
674 // (**NEVER** update `prev_original_span` because it affects the assumptions
675 // about how the `CoverageSpan`s are ordered.)
676 self.prev_mut().span
= self.prev().span
.with_lo(right_cutoff
);
677 debug
!(" Mutated prev.span to start after the closure. prev={:?}", self.prev());
678 for dup
in pending_dups
.iter_mut() {
679 debug
!(" ...and at least one overlapping dup={:?}", dup
);
680 dup
.span
= dup
.span
.with_lo(right_cutoff
);
682 self.pending_dups
.append(&mut pending_dups
);
683 let closure_covspan
= self.take_curr();
684 self.push_refined_span(closure_covspan
); // since self.prev() was already updated
686 pending_dups
.clear();
690 /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
691 /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
692 /// If prev.span() was merged into other spans (with matching BCB, for instance),
693 /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`.
694 /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
695 /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is
696 /// not as important as knowing that `prev()` **used to have the same span** as `curr(),
697 /// which means their sort order is still meaningful for determining the dominator
700 /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
701 /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
702 /// until their disposition is determined. In this latter case, the `prev` dup is moved into
703 /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
704 fn hold_pending_dups_unless_dominated(&mut self) {
705 // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
706 // impossible for `curr` to dominate any previous `CoverageSpan`.
707 debug_assert
!(!self.span_bcb_is_dominated_by(self.prev(), self.curr()));
709 let initial_pending_count
= self.pending_dups
.len();
710 if initial_pending_count
> 0 {
711 let mut pending_dups
= self.pending_dups
.split_off(0);
712 pending_dups
.retain(|dup
| !self.span_bcb_is_dominated_by(self.curr(), dup
));
713 self.pending_dups
.append(&mut pending_dups
);
714 if self.pending_dups
.len() < initial_pending_count
{
716 " discarded {} of {} pending_dups that dominated curr",
717 initial_pending_count
- self.pending_dups
.len(),
718 initial_pending_count
723 if self.span_bcb_is_dominated_by(self.curr(), self.prev()) {
725 " different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
728 self.cutoff_prev_at_overlapping_curr();
729 // If one span dominates the other, associate the span with the code from the dominated
730 // block only (`curr`), and discard the overlapping portion of the `prev` span. (Note
731 // that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still
732 // be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.)
736 // x if x < 1 => { ... }
739 // The span for the first `x` is referenced by both the pattern block (every time it is
740 // evaluated) and the arm code (only when matched). The counter will be applied only to
741 // the dominated block. This allows coverage to track and highlight things like the
742 // assignment of `x` above, if the branch is matched, making `x` available to the arm
743 // code; and to track and highlight the question mark `?` "try" operator at the end of
744 // a function call returning a `Result`, so the `?` is covered when the function returns
745 // an `Err`, and not counted as covered if the function always returns `Ok`.
747 // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.)
748 // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as
749 // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added.
751 " different bcbs but SAME spans, and neither dominates, so keep curr for \
752 next iter, and, pending upcoming spans (unless overlapping) add prev={:?}",
755 let prev
= self.take_prev();
756 self.pending_dups
.push(prev
);
760 /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
761 /// statements that end before `curr.lo()` (if any), and add the portion of the
762 /// combined span for those statements. Any other statements have overlapping spans
763 /// that can be ignored because `curr` and/or other upcoming statements/spans inside
764 /// the overlap area will produce their own counters. This disambiguation process
765 /// avoids injecting multiple counters for overlapping spans, and the potential for
767 fn cutoff_prev_at_overlapping_curr(&mut self) {
769 " different bcbs, overlapping spans, so ignore/drop pending and only add prev \
770 if it has statements that end before curr; prev={:?}",
773 if self.pending_dups
.is_empty() {
774 let curr_span
= self.curr().span
;
775 self.prev_mut().cutoff_statements_at(curr_span
.lo());
776 if self.prev().coverage_statements
.is_empty() {
777 debug
!(" ... no non-overlapping statements to add");
779 debug
!(" ... adding modified prev={:?}", self.prev());
780 let prev
= self.take_prev();
781 self.push_refined_span(prev
);
784 // with `pending_dups`, `prev` cannot have any statements that don't overlap
785 self.pending_dups
.clear();
789 fn span_bcb_is_dominated_by(&self, covspan
: &CoverageSpan
, dom_covspan
: &CoverageSpan
) -> bool
{
790 self.basic_coverage_blocks
.is_dominated_by(covspan
.bcb
, dom_covspan
.bcb
)
794 /// If the MIR `Statement` has a span contributive to computing coverage spans,
795 /// return it; otherwise return `None`.
796 pub(super) fn filtered_statement_span(statement
: &Statement
<'_
>) -> Option
<Span
> {
797 match statement
.kind
{
798 // These statements have spans that are often outside the scope of the executed source code
799 // for their parent `BasicBlock`.
800 StatementKind
::StorageLive(_
)
801 | StatementKind
::StorageDead(_
)
802 // Coverage should not be encountered, but don't inject coverage coverage
803 | StatementKind
::Coverage(_
)
805 | StatementKind
::Nop
=> None
,
807 // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
808 // statements be more consistent?
810 // FakeReadCause::ForGuardBinding, in this example:
812 // x if x < 1 => { ... }
814 // The BasicBlock within the match arm code included one of these statements, but the span
815 // for it covered the `1` in this source. The actual statements have nothing to do with that
817 // FakeRead(ForGuardBinding, _4);
819 // _4 = &_1; (at the span for the first `x`)
820 // and `_1` is the `Place` for `somenum`.
822 // If and when the Issue is resolved, remove this special case match pattern:
823 StatementKind
::FakeRead(box (cause
, _
)) if cause
== FakeReadCause
::ForGuardBinding
=> None
,
825 // Retain spans from all other statements
826 StatementKind
::FakeRead(box (_
, _
)) // Not including `ForGuardBinding`
827 | StatementKind
::CopyNonOverlapping(..)
828 | StatementKind
::Assign(_
)
829 | StatementKind
::SetDiscriminant { .. }
830 | StatementKind
::Deinit(..)
831 | StatementKind
::Retag(_
, _
)
832 | StatementKind
::AscribeUserType(_
, _
) => {
833 Some(statement
.source_info
.span
)
838 /// If the MIR `Terminator` has a span contributive to computing coverage spans,
839 /// return it; otherwise return `None`.
840 pub(super) fn filtered_terminator_span(terminator
: &Terminator
<'_
>) -> Option
<Span
> {
841 match terminator
.kind
{
842 // These terminators have spans that don't positively contribute to computing a reasonable
843 // span of actually executed source code. (For example, SwitchInt terminators extracted from
844 // an `if condition { block }` has a span that includes the executed block, if true,
845 // but for coverage, the code region executed, up to *and* through the SwitchInt,
846 // actually stops before the if's block.)
847 TerminatorKind
::Unreachable
// Unreachable blocks are not connected to the MIR CFG
848 | TerminatorKind
::Assert { .. }
849 | TerminatorKind
::Drop { .. }
850 | TerminatorKind
::DropAndReplace { .. }
851 | TerminatorKind
::SwitchInt { .. }
852 // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
853 | TerminatorKind
::FalseEdge { .. }
854 | TerminatorKind
::Goto { .. }
=> None
,
856 // Call `func` operand can have a more specific span when part of a chain of calls
857 | TerminatorKind
::Call { ref func, .. }
=> {
858 let mut span
= terminator
.source_info
.span
;
859 if let mir
::Operand
::Constant(box constant
) = func
{
860 if constant
.span
.lo() > span
.lo() {
861 span
= span
.with_lo(constant
.span
.lo());
867 // Retain spans from all other terminators
868 TerminatorKind
::Resume
869 | TerminatorKind
::Abort
870 | TerminatorKind
::Return
871 | TerminatorKind
::Yield { .. }
872 | TerminatorKind
::GeneratorDrop
873 | TerminatorKind
::FalseUnwind { .. }
874 | TerminatorKind
::InlineAsm { .. }
=> {
875 Some(terminator
.source_info
.span
)
880 /// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
881 /// within the function's body source. This span is guaranteed to be contained
882 /// within, or equal to, the `body_span`. If the extrapolated span is not
883 /// contained within the `body_span`, the `body_span` is returned.
885 /// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
888 pub(super) fn function_source_span(span
: Span
, body_span
: Span
) -> Span
{
889 let original_span
= original_sp(span
, body_span
).with_ctxt(body_span
.ctxt());
890 if body_span
.contains(original_span
) { original_span }
else { body_span }