]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/transform/coverage/spans.rs
ddbd1680430d29f40b4e44c05cc9bf3409a3d6b7
[rust.git] / compiler / rustc_mir / src / transform / coverage / spans.rs
1 use super::debug::term_type;
2 use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
3
4 use crate::util::spanview::source_range_no_file;
5
6 use rustc_data_structures::graph::WithNumNodes;
7 use rustc_middle::mir::{
8     self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
9     TerminatorKind,
10 };
11 use rustc_middle::ty::TyCtxt;
12
13 use rustc_span::source_map::original_sp;
14 use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
15
16 use std::cmp::Ordering;
17
18 #[derive(Debug, Copy, Clone)]
19 pub(super) enum CoverageStatement {
20     Statement(BasicBlock, Span, usize),
21     Terminator(BasicBlock, Span),
22 }
23
24 impl CoverageStatement {
25     pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
26         match *self {
27             Self::Statement(bb, span, stmt_index) => {
28                 let stmt = &mir_body[bb].statements[stmt_index];
29                 format!(
30                     "{}: @{}[{}]: {:?}",
31                     source_range_no_file(tcx, &span),
32                     bb.index(),
33                     stmt_index,
34                     stmt
35                 )
36             }
37             Self::Terminator(bb, span) => {
38                 let term = mir_body[bb].terminator();
39                 format!(
40                     "{}: @{}.{}: {:?}",
41                     source_range_no_file(tcx, &span),
42                     bb.index(),
43                     term_type(&term.kind),
44                     term.kind
45                 )
46             }
47         }
48     }
49
50     pub fn span(&self) -> &Span {
51         match self {
52             Self::Statement(_, span, _) | Self::Terminator(_, span) => span,
53         }
54     }
55 }
56
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.
62 ///
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 {
69     pub span: Span,
70     pub is_macro_expansion: bool,
71     pub bcb: BasicCoverageBlock,
72     pub coverage_statements: Vec<CoverageStatement>,
73     pub is_closure: bool,
74 }
75
76 impl CoverageSpan {
77     pub fn for_fn_sig(fn_sig_span: Span) -> Self {
78         // Whether the function signature is from a macro or not, it should not be treated like
79         // macro-expanded statements and terminators.
80         let is_macro_expansion = false;
81         Self {
82             span: fn_sig_span,
83             is_macro_expansion,
84             bcb: START_BCB,
85             coverage_statements: vec![],
86             is_closure: false,
87         }
88     }
89
90     pub fn for_statement(
91         statement: &Statement<'tcx>,
92         span: Span,
93         is_macro_expansion: bool,
94         bcb: BasicCoverageBlock,
95         bb: BasicBlock,
96         stmt_index: usize,
97     ) -> Self {
98         let is_closure = match statement.kind {
99             StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
100                 AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
101                 _ => false,
102             },
103             _ => false,
104         };
105
106         Self {
107             span,
108             is_macro_expansion,
109             bcb,
110             coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
111             is_closure,
112         }
113     }
114
115     pub fn for_terminator(
116         span: Span,
117         is_macro_expansion: bool,
118         bcb: BasicCoverageBlock,
119         bb: BasicBlock,
120     ) -> Self {
121         Self {
122             span,
123             is_macro_expansion,
124             bcb,
125             coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
126             is_closure: false,
127         }
128     }
129
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);
134     }
135
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())
140         {
141             self.span = self.span.with_hi(highest_covstmt.span().hi());
142         }
143     }
144
145     #[inline]
146     pub fn is_mergeable(&self, other: &Self) -> bool {
147         self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure)
148     }
149
150     #[inline]
151     pub fn is_in_same_bcb(&self, other: &Self) -> bool {
152         self.bcb == other.bcb
153     }
154
155     pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
156         format!(
157             "{}\n    {}",
158             source_range_no_file(tcx, &self.span),
159             self.format_coverage_statements(tcx, mir_body).replace("\n", "\n    "),
160         )
161     }
162
163     pub fn format_coverage_statements(
164         &self,
165         tcx: TyCtxt<'tcx>,
166         mir_body: &'a mir::Body<'tcx>,
167     ) -> String {
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),
172         });
173         sorted_coverage_statements
174             .iter()
175             .map(|covstmt| covstmt.format(tcx, mir_body))
176             .collect::<Vec<_>>()
177             .join("\n")
178     }
179 }
180
181 /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a
182 /// minimal set of `CoverageSpan`s, using the BCB CFG to determine where it is safe and useful to:
183 ///
184 ///  * Remove duplicate source code coverage regions
185 ///  * Merge spans that represent continuous (both in source code and control flow), non-branching
186 ///    execution
187 ///  * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
188 pub struct CoverageSpans<'a, 'tcx> {
189     /// The MIR, used to look up `BasicBlockData`.
190     mir_body: &'a mir::Body<'tcx>,
191
192     /// A `Span` covering the signature of function for the MIR.
193     fn_sig_span: Span,
194
195     /// A `Span` covering the function body of the MIR (typically from left curly brace to right
196     /// curly brace).
197     body_span: Span,
198
199     /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
200     basic_coverage_blocks: &'a CoverageGraph,
201
202     /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative
203     /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
204     sorted_spans_iter: Option<std::vec::IntoIter<CoverageSpan>>,
205
206     /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the
207     /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to
208     /// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next
209     /// iteration.
210     some_curr: Option<CoverageSpan>,
211
212     /// The original `span` for `curr`, in case the `curr` span is modified.
213     curr_original_span: Span,
214
215     /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
216     /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
217     some_prev: Option<CoverageSpan>,
218
219     /// Assigned from `curr_original_span` from the previous iteration.
220     prev_original_span: Span,
221
222     /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
223     /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
224     /// If a new `curr` span also fits this criteria (compared to an existing list of
225     /// `pending_dups`), that `curr` `CoverageSpan` moves to `prev` before possibly being added to
226     /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups`
227     /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev`
228     /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a
229     /// `prev` with a matching `Span`)
230     pending_dups: Vec<CoverageSpan>,
231
232     /// The final `CoverageSpan`s to add to the coverage map. A `Counter` or `Expression`
233     /// will also be injected into the MIR for each `CoverageSpan`.
234     refined_spans: Vec<CoverageSpan>,
235 }
236
237 impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
238     /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
239     /// counted.
240     ///
241     /// The basic steps are:
242     ///
243     /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
244     ///    `BasicCoverageBlockData`.
245     /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
246     ///    are sorted with longer spans before shorter spans; and equal spans are sorted
247     ///    (deterministically) based on "dominator" relationship (if any).
248     /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
249     ///    if another span or spans are already counting the same code region), or should be merged
250     ///    into a broader combined span (because it represents a contiguous, non-branching, and
251     ///    uninterrupted region of source code).
252     ///
253     ///    Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
254     ///    closures have their own MIR, their `Span` in their enclosing function should be left
255     ///    "uncovered".
256     ///
257     /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
258     /// to be).
259     pub(super) fn generate_coverage_spans(
260         mir_body: &'a mir::Body<'tcx>,
261         fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
262         body_span: Span,
263         basic_coverage_blocks: &'a CoverageGraph,
264     ) -> Vec<CoverageSpan> {
265         let mut coverage_spans = CoverageSpans {
266             mir_body,
267             fn_sig_span,
268             body_span,
269             basic_coverage_blocks,
270             sorted_spans_iter: None,
271             refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
272             some_curr: None,
273             curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
274             some_prev: None,
275             prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
276             pending_dups: Vec::new(),
277         };
278
279         let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
280
281         coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
282         coverage_spans.some_prev = coverage_spans.sorted_spans_iter.as_mut().unwrap().next();
283         coverage_spans.prev_original_span =
284             coverage_spans.some_prev.as_ref().expect("at least one span").span;
285
286         coverage_spans.to_refined_spans()
287     }
288
289     fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
290         let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2);
291         for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
292             for coverage_span in self.bcb_to_initial_coverage_spans(bcb, bcb_data) {
293                 initial_spans.push(coverage_span);
294             }
295         }
296
297         if initial_spans.is_empty() {
298             // This can happen if, for example, the function is unreachable (contains only a
299             // `BasicBlock`(s) with an `Unreachable` terminator).
300             return initial_spans;
301         }
302
303         initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span));
304
305         initial_spans.sort_unstable_by(|a, b| {
306             if a.span.lo() == b.span.lo() {
307                 if a.span.hi() == b.span.hi() {
308                     if a.is_in_same_bcb(b) {
309                         Some(Ordering::Equal)
310                     } else {
311                         // Sort equal spans by dominator relationship, in reverse order (so
312                         // dominators always come after the dominated equal spans). When later
313                         // comparing two spans in order, the first will either dominate the second,
314                         // or they will have no dominator relationship.
315                         self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb)
316                     }
317                 } else {
318                     // Sort hi() in reverse order so shorter spans are attempted after longer spans.
319                     // This guarantees that, if a `prev` span overlaps, and is not equal to, a
320                     // `curr` span, the prev span either extends further left of the curr span, or
321                     // they start at the same position and the prev span extends further right of
322                     // the end of the curr span.
323                     b.span.hi().partial_cmp(&a.span.hi())
324                 }
325             } else {
326                 a.span.lo().partial_cmp(&b.span.lo())
327             }
328             .unwrap()
329         });
330
331         initial_spans
332     }
333
334     /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
335     /// de-duplicated `CoverageSpan`s.
336     fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
337         while self.next_coverage_span() {
338             if self.curr().is_mergeable(self.prev()) {
339                 debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
340                 let prev = self.take_prev();
341                 self.curr_mut().merge_from(prev);
342             // Note that curr.span may now differ from curr_original_span
343             } else if self.prev_ends_before_curr() {
344                 debug!(
345                     "  different bcbs and disjoint spans, so keep curr for next iter, and add \
346                     prev={:?}",
347                     self.prev()
348                 );
349                 let prev = self.take_prev();
350                 self.refined_spans.push(prev);
351             } else if self.prev().is_closure {
352                 // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
353                 // next iter
354                 debug!(
355                     "  curr overlaps a closure (prev). Drop curr and keep prev for next iter. \
356                     prev={:?}",
357                     self.prev()
358                 );
359                 self.take_curr();
360             } else if self.curr().is_closure {
361                 self.carve_out_span_for_closure();
362             } else if self.prev_original_span == self.curr().span {
363                 // Note that this compares the new span to `prev_original_span`, which may not
364                 // be the full `prev.span` (if merged during the previous iteration).
365                 if self.prev().is_macro_expansion && self.curr().is_macro_expansion {
366                     // Macros that expand to include branching (such as
367                     // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
368                     // `trace!()) typically generate callee spans with identical
369                     // ranges (typically the full span of the macro) for all
370                     // `BasicBlocks`. This makes it impossible to distinguish
371                     // the condition (`if val1 != val2`) from the optional
372                     // branched statements (such as the call to `panic!()` on
373                     // assert failure). In this case it is better (or less
374                     // worse) to drop the optional branch bcbs and keep the
375                     // non-conditional statements, to count when reached.
376                     debug!(
377                         "  curr and prev are part of a macro expansion, and curr has the same span \
378                         as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
379                         prev={:?}",
380                         self.prev()
381                     );
382                     self.take_curr();
383                 } else {
384                     self.hold_pending_dups_unless_dominated();
385                 }
386             } else {
387                 self.cutoff_prev_at_overlapping_curr();
388             }
389         }
390
391         debug!("    AT END, adding last prev={:?}", self.prev());
392         let prev = self.take_prev();
393         let CoverageSpans { pending_dups, mut refined_spans, .. } = self;
394         for dup in pending_dups {
395             debug!("    ...adding at least one pending dup={:?}", dup);
396             refined_spans.push(dup);
397         }
398
399         // Async functions wrap a closure that implements the body to be executed. The enclosing
400         // function is called and returns an `impl Future` without initially executing any of the
401         // body. To avoid showing the return from the enclosing function as a "covered" return from
402         // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is
403         // excluded. The closure's `Return` is the only one that will be counted. This provides
404         // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
405         // of the function body.)
406         let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() {
407             last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
408         } else {
409             false
410         };
411
412         if !body_ends_with_closure {
413             refined_spans.push(prev);
414         }
415
416         // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
417         // regions for the current function leave room for the closure's own coverage regions
418         // (injected separately, from the closure's own MIR).
419         refined_spans.retain(|covspan| !covspan.is_closure);
420         refined_spans
421     }
422
423     // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
424     // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
425     // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
426     // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
427     // `Statement`s and/or `Terminator`s.)
428     fn bcb_to_initial_coverage_spans(
429         &self,
430         bcb: BasicCoverageBlock,
431         bcb_data: &'a BasicCoverageBlockData,
432     ) -> Vec<CoverageSpan> {
433         bcb_data
434             .basic_blocks
435             .iter()
436             .flat_map(|&bb| {
437                 let data = &self.mir_body[bb];
438                 data.statements
439                     .iter()
440                     .enumerate()
441                     .filter_map(move |(index, statement)| {
442                         filtered_statement_span(statement, self.body_span).map(
443                             |(span, is_macro_expansion)| {
444                                 CoverageSpan::for_statement(
445                                     statement,
446                                     span,
447                                     is_macro_expansion,
448                                     bcb,
449                                     bb,
450                                     index,
451                                 )
452                             },
453                         )
454                     })
455                     .chain(filtered_terminator_span(data.terminator(), self.body_span).map(
456                         |(span, is_macro_expansion)| {
457                             CoverageSpan::for_terminator(span, is_macro_expansion, bcb, bb)
458                         },
459                     ))
460             })
461             .collect()
462     }
463
464     fn curr(&self) -> &CoverageSpan {
465         self.some_curr
466             .as_ref()
467             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
468     }
469
470     fn curr_mut(&mut self) -> &mut CoverageSpan {
471         self.some_curr
472             .as_mut()
473             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
474     }
475
476     fn prev(&self) -> &CoverageSpan {
477         self.some_prev
478             .as_ref()
479             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
480     }
481
482     fn prev_mut(&mut self) -> &mut CoverageSpan {
483         self.some_prev
484             .as_mut()
485             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
486     }
487
488     fn take_prev(&mut self) -> CoverageSpan {
489         self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
490     }
491
492     /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
493     /// `pending_dups` spans), then one of the following two things happened during the previous
494     /// iteration:
495     ///   * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups
496     ///     (in which case there should be at least two spans in `pending_dups`); or
497     ///   * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case
498     ///     `pending_dups` could have as few as one span)
499     /// In either case, no more spans will match the span of `pending_dups`, so
500     /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
501     fn check_pending_dups(&mut self) {
502         if let Some(dup) = self.pending_dups.last() {
503             if dup.span != self.prev().span {
504                 debug!(
505                     "    SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
506                     previous iteration, or prev started a new disjoint span"
507                 );
508                 if dup.span.hi() <= self.curr().span.lo() {
509                     let pending_dups = self.pending_dups.split_off(0);
510                     for dup in pending_dups.into_iter() {
511                         debug!("    ...adding at least one pending={:?}", dup);
512                         self.refined_spans.push(dup);
513                     }
514                 } else {
515                     self.pending_dups.clear();
516                 }
517             }
518         }
519     }
520
521     /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
522     fn next_coverage_span(&mut self) -> bool {
523         if let Some(curr) = self.some_curr.take() {
524             self.some_prev = Some(curr);
525             self.prev_original_span = self.curr_original_span;
526         }
527         while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
528             debug!("FOR curr={:?}", curr);
529             if self.prev_starts_after_next(&curr) {
530                 debug!(
531                     "  prev.span starts after curr.span, so curr will be dropped (skipping past \
532                     closure?); prev={:?}",
533                     self.prev()
534                 );
535             } else {
536                 // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
537                 // by `self.curr_mut().merge_from(prev)`.
538                 self.curr_original_span = curr.span;
539                 self.some_curr.replace(curr);
540                 self.check_pending_dups();
541                 return true;
542             }
543         }
544         false
545     }
546
547     /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
548     /// `curr` coverage span.
549     fn take_curr(&mut self) -> CoverageSpan {
550         self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
551     }
552
553     /// Returns true if the curr span should be skipped because prev has already advanced beyond the
554     /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
555     /// of code, such as skipping past a closure.
556     fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool {
557         self.prev().span.lo() > next_curr.span.lo()
558     }
559
560     /// Returns true if the curr span starts past the end of the prev span, which means they don't
561     /// overlap, so we now know the prev can be added to the refined coverage spans.
562     fn prev_ends_before_curr(&self) -> bool {
563         self.prev().span.hi() <= self.curr().span.lo()
564     }
565
566     /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
567     /// `prev`'s span. (The closure's coverage counters will be injected when processing the
568     /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
569     /// extends to the right of the closure, update `prev` to that portion of the span. For any
570     /// `pending_dups`, repeat the same process.
571     fn carve_out_span_for_closure(&mut self) {
572         let curr_span = self.curr().span;
573         let left_cutoff = curr_span.lo();
574         let right_cutoff = curr_span.hi();
575         let has_pre_closure_span = self.prev().span.lo() < right_cutoff;
576         let has_post_closure_span = self.prev().span.hi() > right_cutoff;
577         let mut pending_dups = self.pending_dups.split_off(0);
578         if has_pre_closure_span {
579             let mut pre_closure = self.prev().clone();
580             pre_closure.span = pre_closure.span.with_hi(left_cutoff);
581             debug!("  prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
582             if !pending_dups.is_empty() {
583                 for mut dup in pending_dups.iter().cloned() {
584                     dup.span = dup.span.with_hi(left_cutoff);
585                     debug!("    ...and at least one pre_closure dup={:?}", dup);
586                     self.refined_spans.push(dup);
587                 }
588             }
589             self.refined_spans.push(pre_closure);
590         }
591         if has_post_closure_span {
592             // Update prev.span to start after the closure (and discard curr)
593             self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
594             self.prev_original_span = self.prev().span;
595             for dup in pending_dups.iter_mut() {
596                 dup.span = dup.span.with_lo(right_cutoff);
597             }
598             self.pending_dups.append(&mut pending_dups);
599             let closure_covspan = self.take_curr();
600             self.refined_spans.push(closure_covspan); // since self.prev() was already updated
601         } else {
602             pending_dups.clear();
603         }
604     }
605
606     /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
607     /// `pending_dups` spans, if any); but keep in mind, `prev.span` may start at a `Span.lo()` that
608     /// is less than (further left of) `prev_original_span.lo()`.
609     ///
610     /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
611     /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
612     /// until their disposition is determined. In this latter case, the `prev` dup is moved into
613     /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
614     fn hold_pending_dups_unless_dominated(&mut self) {
615         // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
616         // impossible for `curr` to dominate any previous `CoverageSpan`.
617         debug_assert!(!self.span_bcb_is_dominated_by(self.prev(), self.curr()));
618
619         let initial_pending_count = self.pending_dups.len();
620         if initial_pending_count > 0 {
621             let mut pending_dups = self.pending_dups.split_off(0);
622             pending_dups.retain(|dup| !self.span_bcb_is_dominated_by(self.curr(), dup));
623             self.pending_dups.append(&mut pending_dups);
624             if self.pending_dups.len() < initial_pending_count {
625                 debug!(
626                     "  discarded {} of {} pending_dups that dominated curr",
627                     initial_pending_count - self.pending_dups.len(),
628                     initial_pending_count
629                 );
630             }
631         }
632
633         if self.span_bcb_is_dominated_by(self.curr(), self.prev()) {
634             debug!(
635                 "  different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
636                 self.prev()
637             );
638             self.cutoff_prev_at_overlapping_curr();
639         // If one span dominates the other, assocate the span with the code from the dominated
640         // block only (`curr`), and discard the overlapping portion of the `prev` span. (Note
641         // that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still
642         // be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.)
643         //
644         // For example:
645         //     match somenum {
646         //         x if x < 1 => { ... }
647         //     }...
648         //
649         // The span for the first `x` is referenced by both the pattern block (every time it is
650         // evaluated) and the arm code (only when matched). The counter will be applied only to
651         // the dominated block. This allows coverage to track and highlight things like the
652         // assignment of `x` above, if the branch is matched, making `x` available to the arm
653         // code; and to track and highlight the question mark `?` "try" operator at the end of
654         // a function call returning a `Result`, so the `?` is covered when the function returns
655         // an `Err`, and not counted as covered if the function always returns `Ok`.
656         } else {
657             // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.)
658             // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as
659             // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added.
660             debug!(
661                 "  different bcbs but SAME spans, and neither dominates, so keep curr for \
662                 next iter, and, pending upcoming spans (unless overlapping) add prev={:?}",
663                 self.prev()
664             );
665             let prev = self.take_prev();
666             self.pending_dups.push(prev);
667         }
668     }
669
670     /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
671     /// statements that end before `curr.lo()` (if any), and add the portion of the
672     /// combined span for those statements. Any other statements have overlapping spans
673     /// that can be ignored because `curr` and/or other upcoming statements/spans inside
674     /// the overlap area will produce their own counters. This disambiguation process
675     /// avoids injecting multiple counters for overlapping spans, and the potential for
676     /// double-counting.
677     fn cutoff_prev_at_overlapping_curr(&mut self) {
678         debug!(
679             "  different bcbs, overlapping spans, so ignore/drop pending and only add prev \
680             if it has statements that end before curr; prev={:?}",
681             self.prev()
682         );
683         if self.pending_dups.is_empty() {
684             let curr_span = self.curr().span;
685             self.prev_mut().cutoff_statements_at(curr_span.lo());
686             if self.prev().coverage_statements.is_empty() {
687                 debug!("  ... no non-overlapping statements to add");
688             } else {
689                 debug!("  ... adding modified prev={:?}", self.prev());
690                 let prev = self.take_prev();
691                 self.refined_spans.push(prev);
692             }
693         } else {
694             // with `pending_dups`, `prev` cannot have any statements that don't overlap
695             self.pending_dups.clear();
696         }
697     }
698
699     fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &CoverageSpan) -> bool {
700         self.basic_coverage_blocks.is_dominated_by(covspan.bcb, dom_covspan.bcb)
701     }
702 }
703
704 pub(super) fn filtered_statement_span(
705     statement: &'a Statement<'tcx>,
706     body_span: Span,
707 ) -> Option<(Span, bool)> {
708     match statement.kind {
709         // These statements have spans that are often outside the scope of the executed source code
710         // for their parent `BasicBlock`.
711         StatementKind::StorageLive(_)
712         | StatementKind::StorageDead(_)
713         // Coverage should not be encountered, but don't inject coverage coverage
714         | StatementKind::Coverage(_)
715         // Ignore `Nop`s
716         | StatementKind::Nop => None,
717
718         // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
719         // statements be more consistent?
720         //
721         // FakeReadCause::ForGuardBinding, in this example:
722         //     match somenum {
723         //         x if x < 1 => { ... }
724         //     }...
725         // The BasicBlock within the match arm code included one of these statements, but the span
726         // for it covered the `1` in this source. The actual statements have nothing to do with that
727         // source span:
728         //     FakeRead(ForGuardBinding, _4);
729         // where `_4` is:
730         //     _4 = &_1; (at the span for the first `x`)
731         // and `_1` is the `Place` for `somenum`.
732         //
733         // If and when the Issue is resolved, remove this special case match pattern:
734         StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None,
735
736         // Retain spans from all other statements
737         StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
738         | StatementKind::CopyNonOverlapping(..)
739         | StatementKind::Assign(_)
740         | StatementKind::SetDiscriminant { .. }
741         | StatementKind::LlvmInlineAsm(_)
742         | StatementKind::Retag(_, _)
743         | StatementKind::AscribeUserType(_, _) => {
744             Some(function_source_span(statement.source_info.span, body_span))
745         }
746     }
747 }
748
749 pub(super) fn filtered_terminator_span(
750     terminator: &'a Terminator<'tcx>,
751     body_span: Span,
752 ) -> Option<(Span, bool)> {
753     match terminator.kind {
754         // These terminators have spans that don't positively contribute to computing a reasonable
755         // span of actually executed source code. (For example, SwitchInt terminators extracted from
756         // an `if condition { block }` has a span that includes the executed block, if true,
757         // but for coverage, the code region executed, up to *and* through the SwitchInt,
758         // actually stops before the if's block.)
759         TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
760         | TerminatorKind::Assert { .. }
761         | TerminatorKind::Drop { .. }
762         | TerminatorKind::DropAndReplace { .. }
763         | TerminatorKind::SwitchInt { .. }
764         // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
765         | TerminatorKind::FalseEdge { .. }
766         | TerminatorKind::Goto { .. } => None,
767
768         // Call `func` operand can have a more specific span when part of a chain of calls
769         | TerminatorKind::Call { ref func, .. } => {
770             let mut span = terminator.source_info.span;
771             if let mir::Operand::Constant(box constant) = func {
772                 if constant.span.lo() > span.lo() {
773                     span = span.with_lo(constant.span.lo());
774                 }
775             }
776             Some(function_source_span(span, body_span))
777         }
778
779         // Retain spans from all other terminators
780         TerminatorKind::Resume
781         | TerminatorKind::Abort
782         | TerminatorKind::Return
783         | TerminatorKind::Yield { .. }
784         | TerminatorKind::GeneratorDrop
785         | TerminatorKind::FalseUnwind { .. }
786         | TerminatorKind::InlineAsm { .. } => {
787             Some(function_source_span(terminator.source_info.span, body_span))
788         }
789     }
790 }
791
792 #[inline]
793 fn function_source_span(span: Span, body_span: Span) -> (Span, bool) {
794     let is_macro_expansion = span.ctxt() != body_span.ctxt()
795         && if let ExpnKind::Macro(MacroKind::Bang, _) = span.ctxt().outer_expn_data().kind {
796             true
797         } else {
798             false
799         };
800     let span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
801     (if body_span.contains(span) { span } else { body_span }, is_macro_expansion)
802 }