]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_transform/src/coverage/spans.rs
Rollup merge of #107125 - WaffleLapkin:expect_an_item_in_your_hir_by_the_next_morning...
[rust.git] / compiler / rustc_mir_transform / src / coverage / spans.rs
1 use super::debug::term_type;
2 use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
3
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,
9     TerminatorKind,
10 };
11 use rustc_middle::ty::TyCtxt;
12 use rustc_span::source_map::original_sp;
13 use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
14
15 use std::cell::RefCell;
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<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &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 /// `dominates()` the `BasicBlock`s in this `CoverageSpan`.
67 #[derive(Debug, Clone)]
68 pub(super) struct CoverageSpan {
69     pub span: Span,
70     pub expn_span: Span,
71     pub current_macro_or_none: RefCell<Option<Option<Symbol>>>,
72     pub bcb: BasicCoverageBlock,
73     pub coverage_statements: Vec<CoverageStatement>,
74     pub is_closure: bool,
75 }
76
77 impl CoverageSpan {
78     pub fn for_fn_sig(fn_sig_span: Span) -> Self {
79         Self {
80             span: fn_sig_span,
81             expn_span: fn_sig_span,
82             current_macro_or_none: Default::default(),
83             bcb: START_BCB,
84             coverage_statements: vec![],
85             is_closure: false,
86         }
87     }
88
89     pub fn for_statement(
90         statement: &Statement<'_>,
91         span: Span,
92         expn_span: Span,
93         bcb: BasicCoverageBlock,
94         bb: BasicBlock,
95         stmt_index: usize,
96     ) -> Self {
97         let is_closure = match statement.kind {
98             StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
99                 matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _))
100             }
101             _ => false,
102         };
103
104         Self {
105             span,
106             expn_span,
107             current_macro_or_none: Default::default(),
108             bcb,
109             coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
110             is_closure,
111         }
112     }
113
114     pub fn for_terminator(
115         span: Span,
116         expn_span: Span,
117         bcb: BasicCoverageBlock,
118         bb: BasicBlock,
119     ) -> Self {
120         Self {
121             span,
122             expn_span,
123             current_macro_or_none: Default::default(),
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<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &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<'tcx>(
164         &self,
165         tcx: TyCtxt<'tcx>,
166         mir_body: &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.iter().map(|covstmt| covstmt.format(tcx, mir_body)).join("\n")
174     }
175
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
179             .borrow_mut()
180             .get_or_insert_with(|| {
181                 if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
182                     self.expn_span.ctxt().outer_expn_data().kind
183                 {
184                     return Some(current_macro);
185                 }
186                 None
187             })
188             .map(|symbol| symbol)
189     }
190
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
195             .expn_span
196             .parent_callsite()
197             .unwrap_or_else(|| bug!("macro must have a parent"))
198             .eq_ctxt(body_span)
199         {
200             return Some(current_macro);
201         }
202         None
203     }
204
205     pub fn is_macro_expansion(&self) -> bool {
206         self.current_macro().is_some()
207     }
208 }
209
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:
212 ///
213 ///  * Remove duplicate source code coverage regions
214 ///  * Merge spans that represent continuous (both in source code and control flow), non-branching
215 ///    execution
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>,
220
221     /// A `Span` covering the signature of function for the MIR.
222     fn_sig_span: Span,
223
224     /// A `Span` covering the function body of the MIR (typically from left curly brace to right
225     /// curly brace).
226     body_span: Span,
227
228     /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
229     basic_coverage_blocks: &'a CoverageGraph,
230
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>>,
234
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
238     /// iteration.
239     some_curr: Option<CoverageSpan>,
240
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()`
243     /// is mutated.
244     curr_original_span: Span,
245
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>,
249
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()`
252     /// is mutated.
253     prev_original_span: Span,
254
255     /// A copy of the expn_span from the prior iteration.
256     prev_expn_span: Option<Span>,
257
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>,
267
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>,
271 }
272
273 impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
274     /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
275     /// counted.
276     ///
277     /// The basic steps are:
278     ///
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).
288     ///
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
291     ///    "uncovered".
292     ///
293     /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
294     /// to be).
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`
298         body_span: Span,
299         basic_coverage_blocks: &'a CoverageGraph,
300     ) -> Vec<CoverageSpan> {
301         let mut coverage_spans = CoverageSpans {
302             mir_body,
303             fn_sig_span,
304             body_span,
305             basic_coverage_blocks,
306             sorted_spans_iter: None,
307             refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
308             some_curr: None,
309             curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
310             some_prev: None,
311             prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
312             prev_expn_span: None,
313             pending_dups: Vec::new(),
314         };
315
316         let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
317
318         coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
319
320         coverage_spans.to_refined_spans()
321     }
322
323     fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
324         let mut initial_spans =
325             Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks.len() * 2);
326         for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
327             initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data));
328         }
329
330         if initial_spans.is_empty() {
331             // This can happen if, for example, the function is unreachable (contains only a
332             // `BasicBlock`(s) with an `Unreachable` terminator).
333             return initial_spans;
334         }
335
336         initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span));
337
338         initial_spans.sort_unstable_by(|a, b| {
339             if a.span.lo() == b.span.lo() {
340                 if a.span.hi() == b.span.hi() {
341                     if a.is_in_same_bcb(b) {
342                         Some(Ordering::Equal)
343                     } else {
344                         // Sort equal spans by dominator relationship (so dominators always come
345                         // before the dominated equal spans). When later comparing two spans in
346                         // order, the first will either dominate the second, or they will have no
347                         // dominator relationship.
348                         self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb)
349                     }
350                 } else {
351                     // Sort hi() in reverse order so shorter spans are attempted after longer spans.
352                     // This guarantees that, if a `prev` span overlaps, and is not equal to, a
353                     // `curr` span, the prev span either extends further left of the curr span, or
354                     // they start at the same position and the prev span extends further right of
355                     // the end of the curr span.
356                     b.span.hi().partial_cmp(&a.span.hi())
357                 }
358             } else {
359                 a.span.lo().partial_cmp(&b.span.lo())
360             }
361             .unwrap()
362         });
363
364         initial_spans
365     }
366
367     /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
368     /// de-duplicated `CoverageSpan`s.
369     fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
370         while self.next_coverage_span() {
371             if self.some_prev.is_none() {
372                 debug!("  initial span");
373                 self.check_invoked_macro_name_span();
374             } else if self.curr().is_mergeable(self.prev()) {
375                 debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
376                 let prev = self.take_prev();
377                 self.curr_mut().merge_from(prev);
378                 self.check_invoked_macro_name_span();
379             // Note that curr.span may now differ from curr_original_span
380             } else if self.prev_ends_before_curr() {
381                 debug!(
382                     "  different bcbs and disjoint spans, so keep curr for next iter, and add \
383                     prev={:?}",
384                     self.prev()
385                 );
386                 let prev = self.take_prev();
387                 self.push_refined_span(prev);
388                 self.check_invoked_macro_name_span();
389             } else if self.prev().is_closure {
390                 // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
391                 // next iter
392                 debug!(
393                     "  curr overlaps a closure (prev). Drop curr and keep prev for next iter. \
394                     prev={:?}",
395                     self.prev()
396                 );
397                 self.take_curr();
398             } else if self.curr().is_closure {
399                 self.carve_out_span_for_closure();
400             } else if self.prev_original_span == self.curr().span {
401                 // Note that this compares the new (`curr`) span to `prev_original_span`.
402                 // In this branch, the actual span byte range of `prev_original_span` is not
403                 // important. What is important is knowing whether the new `curr` span was
404                 // **originally** the same as the original span of `prev()`. The original spans
405                 // reflect their original sort order, and for equal spans, conveys a partial
406                 // ordering based on CFG dominator priority.
407                 if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
408                     // Macros that expand to include branching (such as
409                     // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
410                     // `trace!()) typically generate callee spans with identical
411                     // ranges (typically the full span of the macro) for all
412                     // `BasicBlocks`. This makes it impossible to distinguish
413                     // the condition (`if val1 != val2`) from the optional
414                     // branched statements (such as the call to `panic!()` on
415                     // assert failure). In this case it is better (or less
416                     // worse) to drop the optional branch bcbs and keep the
417                     // non-conditional statements, to count when reached.
418                     debug!(
419                         "  curr and prev are part of a macro expansion, and curr has the same span \
420                         as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
421                         prev={:?}",
422                         self.prev()
423                     );
424                     self.take_curr();
425                 } else {
426                     self.hold_pending_dups_unless_dominated();
427                 }
428             } else {
429                 self.cutoff_prev_at_overlapping_curr();
430                 self.check_invoked_macro_name_span();
431             }
432         }
433
434         debug!("    AT END, adding last prev={:?}", self.prev());
435         let prev = self.take_prev();
436         let pending_dups = self.pending_dups.split_off(0);
437         for dup in pending_dups {
438             debug!("    ...adding at least one pending dup={:?}", dup);
439             self.push_refined_span(dup);
440         }
441
442         // Async functions wrap a closure that implements the body to be executed. The enclosing
443         // function is called and returns an `impl Future` without initially executing any of the
444         // body. To avoid showing the return from the enclosing function as a "covered" return from
445         // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is
446         // excluded. The closure's `Return` is the only one that will be counted. This provides
447         // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
448         // of the function body.)
449         let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
450             last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
451         } else {
452             false
453         };
454
455         if !body_ends_with_closure {
456             self.push_refined_span(prev);
457         }
458
459         // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
460         // regions for the current function leave room for the closure's own coverage regions
461         // (injected separately, from the closure's own MIR).
462         self.refined_spans.retain(|covspan| !covspan.is_closure);
463         self.refined_spans
464     }
465
466     fn push_refined_span(&mut self, covspan: CoverageSpan) {
467         let len = self.refined_spans.len();
468         if len > 0 {
469             let last = &mut self.refined_spans[len - 1];
470             if last.is_mergeable(&covspan) {
471                 debug!(
472                     "merging new refined span with last refined span, last={:?}, covspan={:?}",
473                     last, covspan
474                 );
475                 last.merge_from(covspan);
476                 return;
477             }
478         }
479         self.refined_spans.push(covspan)
480     }
481
482     fn check_invoked_macro_name_span(&mut self) {
483         if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
484             if self.prev_expn_span.map_or(true, |prev_expn_span| {
485                 self.curr().expn_span.ctxt() != prev_expn_span.ctxt()
486             }) {
487                 let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
488                 let after_macro_bang =
489                     merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
490                 let mut macro_name_cov = self.curr().clone();
491                 self.curr_mut().span =
492                     self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang);
493                 macro_name_cov.span =
494                     macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
495                 debug!(
496                     "  and curr starts a new macro expansion, so add a new span just for \
497                             the macro `{}!`, new span={:?}",
498                     visible_macro, macro_name_cov
499                 );
500                 self.push_refined_span(macro_name_cov);
501             }
502         }
503     }
504
505     // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
506     // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
507     // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
508     // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
509     // `Statement`s and/or `Terminator`s.)
510     fn bcb_to_initial_coverage_spans(
511         &self,
512         bcb: BasicCoverageBlock,
513         bcb_data: &'a BasicCoverageBlockData,
514     ) -> Vec<CoverageSpan> {
515         bcb_data
516             .basic_blocks
517             .iter()
518             .flat_map(|&bb| {
519                 let data = &self.mir_body[bb];
520                 data.statements
521                     .iter()
522                     .enumerate()
523                     .filter_map(move |(index, statement)| {
524                         filtered_statement_span(statement).map(|span| {
525                             CoverageSpan::for_statement(
526                                 statement,
527                                 function_source_span(span, self.body_span),
528                                 span,
529                                 bcb,
530                                 bb,
531                                 index,
532                             )
533                         })
534                     })
535                     .chain(filtered_terminator_span(data.terminator()).map(|span| {
536                         CoverageSpan::for_terminator(
537                             function_source_span(span, self.body_span),
538                             span,
539                             bcb,
540                             bb,
541                         )
542                     }))
543             })
544             .collect()
545     }
546
547     fn curr(&self) -> &CoverageSpan {
548         self.some_curr
549             .as_ref()
550             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
551     }
552
553     fn curr_mut(&mut self) -> &mut CoverageSpan {
554         self.some_curr
555             .as_mut()
556             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
557     }
558
559     fn prev(&self) -> &CoverageSpan {
560         self.some_prev
561             .as_ref()
562             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
563     }
564
565     fn prev_mut(&mut self) -> &mut CoverageSpan {
566         self.some_prev
567             .as_mut()
568             .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
569     }
570
571     fn take_prev(&mut self) -> CoverageSpan {
572         self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
573     }
574
575     /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
576     /// `pending_dups` spans), then one of the following two things happened during the previous
577     /// iteration:
578     ///   * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups
579     ///     (in which case there should be at least two spans in `pending_dups`); or
580     ///   * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case
581     ///     `pending_dups` could have as few as one span)
582     /// In either case, no more spans will match the span of `pending_dups`, so
583     /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
584     fn check_pending_dups(&mut self) {
585         if let Some(dup) = self.pending_dups.last() && dup.span != self.prev().span {
586             debug!(
587                 "    SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
588                 previous iteration, or prev started a new disjoint span"
589             );
590             if dup.span.hi() <= self.curr().span.lo() {
591                 let pending_dups = self.pending_dups.split_off(0);
592                 for dup in pending_dups.into_iter() {
593                     debug!("    ...adding at least one pending={:?}", dup);
594                     self.push_refined_span(dup);
595                 }
596             } else {
597                 self.pending_dups.clear();
598             }
599         }
600     }
601
602     /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
603     fn next_coverage_span(&mut self) -> bool {
604         if let Some(curr) = self.some_curr.take() {
605             self.prev_expn_span = Some(curr.expn_span);
606             self.some_prev = Some(curr);
607             self.prev_original_span = self.curr_original_span;
608         }
609         while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
610             debug!("FOR curr={:?}", curr);
611             if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
612                 debug!(
613                     "  prev.span starts after curr.span, so curr will be dropped (skipping past \
614                     closure?); prev={:?}",
615                     self.prev()
616                 );
617             } else {
618                 // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
619                 // by `self.curr_mut().merge_from(prev)`.
620                 self.curr_original_span = curr.span;
621                 self.some_curr.replace(curr);
622                 self.check_pending_dups();
623                 return true;
624             }
625         }
626         false
627     }
628
629     /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
630     /// `curr` coverage span.
631     fn take_curr(&mut self) -> CoverageSpan {
632         self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
633     }
634
635     /// Returns true if the curr span should be skipped because prev has already advanced beyond the
636     /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
637     /// of code, such as skipping past a closure.
638     fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool {
639         self.prev().span.lo() > next_curr.span.lo()
640     }
641
642     /// Returns true if the curr span starts past the end of the prev span, which means they don't
643     /// overlap, so we now know the prev can be added to the refined coverage spans.
644     fn prev_ends_before_curr(&self) -> bool {
645         self.prev().span.hi() <= self.curr().span.lo()
646     }
647
648     /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
649     /// `prev`'s span. (The closure's coverage counters will be injected when processing the
650     /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
651     /// extends to the right of the closure, update `prev` to that portion of the span. For any
652     /// `pending_dups`, repeat the same process.
653     fn carve_out_span_for_closure(&mut self) {
654         let curr_span = self.curr().span;
655         let left_cutoff = curr_span.lo();
656         let right_cutoff = curr_span.hi();
657         let has_pre_closure_span = self.prev().span.lo() < right_cutoff;
658         let has_post_closure_span = self.prev().span.hi() > right_cutoff;
659         let mut pending_dups = self.pending_dups.split_off(0);
660         if has_pre_closure_span {
661             let mut pre_closure = self.prev().clone();
662             pre_closure.span = pre_closure.span.with_hi(left_cutoff);
663             debug!("  prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
664             if !pending_dups.is_empty() {
665                 for mut dup in pending_dups.iter().cloned() {
666                     dup.span = dup.span.with_hi(left_cutoff);
667                     debug!("    ...and at least one pre_closure dup={:?}", dup);
668                     self.push_refined_span(dup);
669                 }
670             }
671             self.push_refined_span(pre_closure);
672         }
673         if has_post_closure_span {
674             // Mutate `prev.span()` to start after the closure (and discard curr).
675             // (**NEVER** update `prev_original_span` because it affects the assumptions
676             // about how the `CoverageSpan`s are ordered.)
677             self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
678             debug!("  Mutated prev.span to start after the closure. prev={:?}", self.prev());
679             for dup in pending_dups.iter_mut() {
680                 debug!("    ...and at least one overlapping dup={:?}", dup);
681                 dup.span = dup.span.with_lo(right_cutoff);
682             }
683             self.pending_dups.append(&mut pending_dups);
684             let closure_covspan = self.take_curr();
685             self.push_refined_span(closure_covspan); // since self.prev() was already updated
686         } else {
687             pending_dups.clear();
688         }
689     }
690
691     /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
692     /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
693     /// If prev.span() was merged into other spans (with matching BCB, for instance),
694     /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`.
695     /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
696     /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is
697     /// not as important as knowing that `prev()` **used to have the same span** as `curr(),
698     /// which means their sort order is still meaningful for determining the dominator
699     /// relationship.
700     ///
701     /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
702     /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
703     /// until their disposition is determined. In this latter case, the `prev` dup is moved into
704     /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
705     fn hold_pending_dups_unless_dominated(&mut self) {
706         // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
707         // impossible for `curr` to dominate any previous `CoverageSpan`.
708         debug_assert!(!self.span_bcb_dominates(self.curr(), self.prev()));
709
710         let initial_pending_count = self.pending_dups.len();
711         if initial_pending_count > 0 {
712             let mut pending_dups = self.pending_dups.split_off(0);
713             pending_dups.retain(|dup| !self.span_bcb_dominates(dup, self.curr()));
714             self.pending_dups.append(&mut pending_dups);
715             if self.pending_dups.len() < initial_pending_count {
716                 debug!(
717                     "  discarded {} of {} pending_dups that dominated curr",
718                     initial_pending_count - self.pending_dups.len(),
719                     initial_pending_count
720                 );
721             }
722         }
723
724         if self.span_bcb_dominates(self.prev(), self.curr()) {
725             debug!(
726                 "  different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
727                 self.prev()
728             );
729             self.cutoff_prev_at_overlapping_curr();
730         // If one span dominates the other, associate the span with the code from the dominated
731         // block only (`curr`), and discard the overlapping portion of the `prev` span. (Note
732         // that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still
733         // be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.)
734         //
735         // For example:
736         //     match somenum {
737         //         x if x < 1 => { ... }
738         //     }...
739         //
740         // The span for the first `x` is referenced by both the pattern block (every time it is
741         // evaluated) and the arm code (only when matched). The counter will be applied only to
742         // the dominated block. This allows coverage to track and highlight things like the
743         // assignment of `x` above, if the branch is matched, making `x` available to the arm
744         // code; and to track and highlight the question mark `?` "try" operator at the end of
745         // a function call returning a `Result`, so the `?` is covered when the function returns
746         // an `Err`, and not counted as covered if the function always returns `Ok`.
747         } else {
748             // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.)
749             // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as
750             // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added.
751             debug!(
752                 "  different bcbs but SAME spans, and neither dominates, so keep curr for \
753                 next iter, and, pending upcoming spans (unless overlapping) add prev={:?}",
754                 self.prev()
755             );
756             let prev = self.take_prev();
757             self.pending_dups.push(prev);
758         }
759     }
760
761     /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
762     /// statements that end before `curr.lo()` (if any), and add the portion of the
763     /// combined span for those statements. Any other statements have overlapping spans
764     /// that can be ignored because `curr` and/or other upcoming statements/spans inside
765     /// the overlap area will produce their own counters. This disambiguation process
766     /// avoids injecting multiple counters for overlapping spans, and the potential for
767     /// double-counting.
768     fn cutoff_prev_at_overlapping_curr(&mut self) {
769         debug!(
770             "  different bcbs, overlapping spans, so ignore/drop pending and only add prev \
771             if it has statements that end before curr; prev={:?}",
772             self.prev()
773         );
774         if self.pending_dups.is_empty() {
775             let curr_span = self.curr().span;
776             self.prev_mut().cutoff_statements_at(curr_span.lo());
777             if self.prev().coverage_statements.is_empty() {
778                 debug!("  ... no non-overlapping statements to add");
779             } else {
780                 debug!("  ... adding modified prev={:?}", self.prev());
781                 let prev = self.take_prev();
782                 self.push_refined_span(prev);
783             }
784         } else {
785             // with `pending_dups`, `prev` cannot have any statements that don't overlap
786             self.pending_dups.clear();
787         }
788     }
789
790     fn span_bcb_dominates(&self, dom_covspan: &CoverageSpan, covspan: &CoverageSpan) -> bool {
791         self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb)
792     }
793 }
794
795 /// If the MIR `Statement` has a span contributive to computing coverage spans,
796 /// return it; otherwise return `None`.
797 pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
798     match statement.kind {
799         // These statements have spans that are often outside the scope of the executed source code
800         // for their parent `BasicBlock`.
801         StatementKind::StorageLive(_)
802         | StatementKind::StorageDead(_)
803         // Coverage should not be encountered, but don't inject coverage coverage
804         | StatementKind::Coverage(_)
805         // Ignore `ConstEvalCounter`s
806         | StatementKind::ConstEvalCounter
807         // Ignore `Nop`s
808         | StatementKind::Nop => None,
809
810         // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
811         // statements be more consistent?
812         //
813         // FakeReadCause::ForGuardBinding, in this example:
814         //     match somenum {
815         //         x if x < 1 => { ... }
816         //     }...
817         // The BasicBlock within the match arm code included one of these statements, but the span
818         // for it covered the `1` in this source. The actual statements have nothing to do with that
819         // source span:
820         //     FakeRead(ForGuardBinding, _4);
821         // where `_4` is:
822         //     _4 = &_1; (at the span for the first `x`)
823         // and `_1` is the `Place` for `somenum`.
824         //
825         // If and when the Issue is resolved, remove this special case match pattern:
826         StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None,
827
828         // Retain spans from all other statements
829         StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
830         | StatementKind::Intrinsic(..)
831         | StatementKind::Assign(_)
832         | StatementKind::SetDiscriminant { .. }
833         | StatementKind::Deinit(..)
834         | StatementKind::Retag(_, _)
835         | StatementKind::AscribeUserType(_, _) => {
836             Some(statement.source_info.span)
837         }
838     }
839 }
840
841 /// If the MIR `Terminator` has a span contributive to computing coverage spans,
842 /// return it; otherwise return `None`.
843 pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
844     match terminator.kind {
845         // These terminators have spans that don't positively contribute to computing a reasonable
846         // span of actually executed source code. (For example, SwitchInt terminators extracted from
847         // an `if condition { block }` has a span that includes the executed block, if true,
848         // but for coverage, the code region executed, up to *and* through the SwitchInt,
849         // actually stops before the if's block.)
850         TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
851         | TerminatorKind::Assert { .. }
852         | TerminatorKind::Drop { .. }
853         | TerminatorKind::DropAndReplace { .. }
854         | TerminatorKind::SwitchInt { .. }
855         // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
856         | TerminatorKind::FalseEdge { .. }
857         | TerminatorKind::Goto { .. } => None,
858
859         // Call `func` operand can have a more specific span when part of a chain of calls
860         | TerminatorKind::Call { ref func, .. } => {
861             let mut span = terminator.source_info.span;
862             if let mir::Operand::Constant(box constant) = func {
863                 if constant.span.lo() > span.lo() {
864                     span = span.with_lo(constant.span.lo());
865                 }
866             }
867             Some(span)
868         }
869
870         // Retain spans from all other terminators
871         TerminatorKind::Resume
872         | TerminatorKind::Abort
873         | TerminatorKind::Return
874         | TerminatorKind::Yield { .. }
875         | TerminatorKind::GeneratorDrop
876         | TerminatorKind::FalseUnwind { .. }
877         | TerminatorKind::InlineAsm { .. } => {
878             Some(terminator.source_info.span)
879         }
880     }
881 }
882
883 /// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
884 /// within the function's body source. This span is guaranteed to be contained
885 /// within, or equal to, the `body_span`. If the extrapolated span is not
886 /// contained within the `body_span`, the `body_span` is returned.
887 ///
888 /// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
889 /// etc.).
890 #[inline]
891 pub(super) fn function_source_span(span: Span, body_span: Span) -> Span {
892     let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
893     if body_span.contains(original_span) { original_span } else { body_span }
894 }