|
| 1 | +use std::iter; |
| 2 | + |
1 | 3 | use rustc_middle::bug; |
2 | 4 | use rustc_middle::mir::coverage::CoverageKind; |
3 | 5 | use rustc_middle::mir::{ |
4 | 6 | self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, |
5 | 7 | }; |
6 | 8 | use rustc_span::{ExpnKind, Span}; |
7 | 9 |
|
8 | | -use crate::coverage::ExtractedHirInfo; |
9 | | -use crate::coverage::graph::{ |
10 | | - BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, |
11 | | -}; |
| 10 | +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; |
12 | 11 | use crate::coverage::spans::Covspan; |
13 | | -use crate::coverage::unexpand::unexpand_into_body_span_with_expn_kind; |
14 | 12 |
|
15 | | -pub(crate) struct ExtractedCovspans { |
16 | | - pub(crate) covspans: Vec<SpanFromMir>, |
| 13 | +#[derive(Debug)] |
| 14 | +pub(crate) struct RawSpanFromMir { |
| 15 | + /// A span that has been extracted from a MIR statement/terminator, but |
| 16 | + /// hasn't been "unexpanded", so it might not lie within the function body |
| 17 | + /// span and might be part of an expansion with a different context. |
| 18 | + pub(crate) raw_span: Span, |
| 19 | + pub(crate) bcb: BasicCoverageBlock, |
17 | 20 | } |
18 | 21 |
|
19 | | -/// Traverses the MIR body to produce an initial collection of coverage-relevant |
20 | | -/// spans, each associated with a node in the coverage graph (BCB) and possibly |
21 | | -/// other metadata. |
22 | | -pub(crate) fn extract_covspans_from_mir( |
23 | | - mir_body: &mir::Body<'_>, |
24 | | - hir_info: &ExtractedHirInfo, |
| 22 | +/// Generates an initial set of coverage spans from the statements and |
| 23 | +/// terminators in the function's MIR body, each associated with its |
| 24 | +/// corresponding node in the coverage graph. |
| 25 | +/// |
| 26 | +/// This is necessarily an inexact process, because MIR isn't designed to |
| 27 | +/// capture source spans at the level of detail we would want for coverage, |
| 28 | +/// but it's good enough to be better than nothing. |
| 29 | +pub(crate) fn extract_raw_spans_from_mir<'tcx>( |
| 30 | + mir_body: &mir::Body<'tcx>, |
25 | 31 | graph: &CoverageGraph, |
26 | | -) -> ExtractedCovspans { |
27 | | - let &ExtractedHirInfo { body_span, .. } = hir_info; |
28 | | - |
29 | | - let mut covspans = vec![]; |
| 32 | +) -> Vec<RawSpanFromMir> { |
| 33 | + let mut raw_spans = vec![]; |
30 | 34 |
|
| 35 | + // We only care about blocks that are part of the coverage graph. |
31 | 36 | for (bcb, bcb_data) in graph.iter_enumerated() { |
32 | | - bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data, &mut covspans); |
33 | | - } |
| 37 | + let make_raw_span = |raw_span: Span| RawSpanFromMir { raw_span, bcb }; |
34 | 38 |
|
35 | | - // Only add the signature span if we found at least one span in the body. |
36 | | - if !covspans.is_empty() { |
37 | | - // If there is no usable signature span, add a fake one (before refinement) |
38 | | - // to avoid an ugly gap between the body start and the first real span. |
39 | | - // FIXME: Find a more principled way to solve this problem. |
40 | | - let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()); |
41 | | - covspans.push(SpanFromMir::for_fn_sig(fn_sig_span)); |
42 | | - } |
| 39 | + // A coverage graph node can consist of multiple basic blocks. |
| 40 | + for &bb in &bcb_data.basic_blocks { |
| 41 | + let bb_data = &mir_body[bb]; |
43 | 42 |
|
44 | | - ExtractedCovspans { covspans } |
45 | | -} |
| 43 | + let statements = bb_data.statements.iter(); |
| 44 | + raw_spans.extend(statements.filter_map(filtered_statement_span).map(make_raw_span)); |
46 | 45 |
|
47 | | -// Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of |
48 | | -// the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One coverage span is generated |
49 | | -// for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will |
50 | | -// merge some coverage spans, at which point a coverage span may represent multiple |
51 | | -// `Statement`s and/or `Terminator`s.) |
52 | | -fn bcb_to_initial_coverage_spans<'a, 'tcx>( |
53 | | - mir_body: &'a mir::Body<'tcx>, |
54 | | - body_span: Span, |
55 | | - bcb: BasicCoverageBlock, |
56 | | - bcb_data: &'a BasicCoverageBlockData, |
57 | | - initial_covspans: &mut Vec<SpanFromMir>, |
58 | | -) { |
59 | | - for &bb in &bcb_data.basic_blocks { |
60 | | - let data = &mir_body[bb]; |
61 | | - |
62 | | - let unexpand = move |expn_span| { |
63 | | - unexpand_into_body_span_with_expn_kind(expn_span, body_span) |
64 | | - // Discard any spans that fill the entire body, because they tend |
65 | | - // to represent compiler-inserted code, e.g. implicitly returning `()`. |
66 | | - .filter(|(span, _)| !span.source_equal(body_span)) |
67 | | - }; |
68 | | - |
69 | | - let mut extract_statement_span = |statement| { |
70 | | - let expn_span = filtered_statement_span(statement)?; |
71 | | - let (span, expn_kind) = unexpand(expn_span)?; |
72 | | - |
73 | | - initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); |
74 | | - Some(()) |
75 | | - }; |
76 | | - for statement in data.statements.iter() { |
77 | | - extract_statement_span(statement); |
| 46 | + // There's only one terminator, but wrap it in an iterator to |
| 47 | + // mirror the handling of statements. |
| 48 | + let terminator = iter::once(bb_data.terminator()); |
| 49 | + raw_spans.extend(terminator.filter_map(filtered_terminator_span).map(make_raw_span)); |
78 | 50 | } |
79 | | - |
80 | | - let mut extract_terminator_span = |terminator| { |
81 | | - let expn_span = filtered_terminator_span(terminator)?; |
82 | | - let (span, expn_kind) = unexpand(expn_span)?; |
83 | | - |
84 | | - initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb)); |
85 | | - Some(()) |
86 | | - }; |
87 | | - extract_terminator_span(data.terminator()); |
88 | 51 | } |
| 52 | + |
| 53 | + raw_spans |
89 | 54 | } |
90 | 55 |
|
91 | 56 | /// If the MIR `Statement` has a span contributive to computing coverage spans, |
@@ -219,7 +184,7 @@ pub(crate) struct SpanFromMir { |
219 | 184 | } |
220 | 185 |
|
221 | 186 | impl SpanFromMir { |
222 | | - fn for_fn_sig(fn_sig_span: Span) -> Self { |
| 187 | + pub(crate) fn for_fn_sig(fn_sig_span: Span) -> Self { |
223 | 188 | Self::new(fn_sig_span, None, START_BCB) |
224 | 189 | } |
225 | 190 |
|
|
0 commit comments