1
1
use crate :: coverageinfo:: ffi:: { Counter , CounterExpression , ExprKind } ;
2
2
3
+ use rustc_data_structures:: captures:: Captures ;
3
4
use rustc_data_structures:: fx:: FxIndexSet ;
4
5
use rustc_index:: bit_set:: BitSet ;
5
6
use rustc_middle:: mir:: coverage:: {
6
7
CodeRegion , CounterId , CovTerm , Expression , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
7
8
} ;
8
9
use rustc_middle:: ty:: Instance ;
10
+ use rustc_span:: Symbol ;
9
11
10
12
/// Holds all of the coverage mapping data associated with a function instance,
11
13
/// collected during traversal of `Coverage` statements in the function's MIR.
12
14
#[ derive( Debug ) ]
13
- pub struct FunctionCoverage < ' tcx > {
15
+ pub struct FunctionCoverageCollector < ' tcx > {
14
16
/// Coverage info that was attached to this function by the instrumentor.
15
17
function_coverage_info : & ' tcx FunctionCoverageInfo ,
16
18
is_used : bool ,
@@ -26,7 +28,7 @@ pub struct FunctionCoverage<'tcx> {
26
28
expressions_seen : BitSet < ExpressionId > ,
27
29
}
28
30
29
- impl < ' tcx > FunctionCoverage < ' tcx > {
31
+ impl < ' tcx > FunctionCoverageCollector < ' tcx > {
30
32
/// Creates a new set of coverage data for a used (called) function.
31
33
pub fn new (
32
34
instance : Instance < ' tcx > ,
@@ -76,11 +78,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
76
78
}
77
79
}
78
80
79
- /// Returns true for a used (called) function, and false for an unused function.
80
- pub fn is_used ( & self ) -> bool {
81
- self . is_used
82
- }
83
-
84
81
/// Marks a counter ID as having been seen in a counter-increment statement.
85
82
#[ instrument( level = "debug" , skip( self ) ) ]
86
83
pub ( crate ) fn mark_counter_id_seen ( & mut self , id : CounterId ) {
@@ -165,72 +162,79 @@ impl<'tcx> FunctionCoverage<'tcx> {
165
162
ZeroExpressions ( zero_expressions)
166
163
}
167
164
165
+ pub ( crate ) fn into_finished ( self ) -> FunctionCoverage < ' tcx > {
166
+ let zero_expressions = self . identify_zero_expressions ( ) ;
167
+ let FunctionCoverageCollector { function_coverage_info, is_used, counters_seen, .. } = self ;
168
+
169
+ FunctionCoverage { function_coverage_info, is_used, counters_seen, zero_expressions }
170
+ }
171
+ }
172
+
173
+ pub ( crate ) struct FunctionCoverage < ' tcx > {
174
+ function_coverage_info : & ' tcx FunctionCoverageInfo ,
175
+ is_used : bool ,
176
+
177
+ counters_seen : BitSet < CounterId > ,
178
+ zero_expressions : ZeroExpressions ,
179
+ }
180
+
181
+ impl < ' tcx > FunctionCoverage < ' tcx > {
182
+ /// Returns true for a used (called) function, and false for an unused function.
183
+ pub ( crate ) fn is_used ( & self ) -> bool {
184
+ self . is_used
185
+ }
186
+
168
187
/// Return the source hash, generated from the HIR node structure, and used to indicate whether
169
188
/// or not the source code structure changed between different compilations.
170
189
pub fn source_hash ( & self ) -> u64 {
171
190
if self . is_used { self . function_coverage_info . function_source_hash } else { 0 }
172
191
}
173
192
174
- /// Generate an array of CounterExpressions, and an iterator over all `Counter`s and their
175
- /// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
176
- /// `CounterMappingRegion`s.
177
- pub fn get_expressions_and_counter_regions (
178
- & self ,
179
- ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & CodeRegion ) > ) {
180
- let zero_expressions = self . identify_zero_expressions ( ) ;
181
-
182
- let counter_expressions = self . counter_expressions ( & zero_expressions) ;
183
- // Expression IDs are indices into `self.expressions`, and on the LLVM
184
- // side they will be treated as indices into `counter_expressions`, so
185
- // the two vectors should correspond 1:1.
186
- assert_eq ! ( self . function_coverage_info. expressions. len( ) , counter_expressions. len( ) ) ;
187
-
188
- let counter_regions = self . counter_regions ( zero_expressions) ;
189
-
190
- ( counter_expressions, counter_regions)
193
+ /// Returns an iterator over all filenames used by this function's mappings.
194
+ pub ( crate ) fn all_file_names ( & self ) -> impl Iterator < Item = Symbol > + Captures < ' _ > {
195
+ self . function_coverage_info . mappings . iter ( ) . map ( |mapping| mapping. code_region . file_name )
191
196
}
192
197
193
198
/// Convert this function's coverage expression data into a form that can be
194
199
/// passed through FFI to LLVM.
195
- fn counter_expressions ( & self , zero_expressions : & ZeroExpressions ) -> Vec < CounterExpression > {
200
+ pub ( crate ) fn counter_expressions (
201
+ & self ,
202
+ ) -> impl Iterator < Item = CounterExpression > + ExactSizeIterator + Captures < ' _ > {
196
203
// We know that LLVM will optimize out any unused expressions before
197
204
// producing the final coverage map, so there's no need to do the same
198
205
// thing on the Rust side unless we're confident we can do much better.
199
206
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
200
207
201
208
let counter_from_operand = |operand : CovTerm | match operand {
202
- CovTerm :: Expression ( id) if zero_expressions. contains ( id) => Counter :: ZERO ,
209
+ CovTerm :: Expression ( id) if self . zero_expressions . contains ( id) => Counter :: ZERO ,
203
210
_ => Counter :: from_term ( operand) ,
204
211
} ;
205
212
206
- self . function_coverage_info
207
- . expressions
208
- . iter ( )
209
- . map ( |& Expression { lhs, op, rhs } | CounterExpression {
213
+ self . function_coverage_info . expressions . iter ( ) . map ( move |& Expression { lhs, op, rhs } | {
214
+ CounterExpression {
210
215
lhs : counter_from_operand ( lhs) ,
211
216
kind : match op {
212
217
Op :: Add => ExprKind :: Add ,
213
218
Op :: Subtract => ExprKind :: Subtract ,
214
219
} ,
215
220
rhs : counter_from_operand ( rhs) ,
216
- } )
217
- . collect :: < Vec < _ > > ( )
221
+ }
222
+ } )
218
223
}
219
224
220
225
/// Converts this function's coverage mappings into an intermediate form
221
226
/// that will be used by `mapgen` when preparing for FFI.
222
- fn counter_regions (
227
+ pub ( crate ) fn counter_regions (
223
228
& self ,
224
- zero_expressions : ZeroExpressions ,
225
- ) -> impl Iterator < Item = ( Counter , & CodeRegion ) > {
229
+ ) -> impl Iterator < Item = ( Counter , & CodeRegion ) > + ExactSizeIterator {
226
230
// Historically, mappings were stored directly in counter/expression
227
231
// statements in MIR, and MIR optimizations would sometimes remove them.
228
232
// That's mostly no longer true, so now we detect cases where that would
229
233
// have happened, and zero out the corresponding mappings here instead.
230
234
let counter_for_term = move |term : CovTerm | {
231
235
let force_to_zero = match term {
232
236
CovTerm :: Counter ( id) => !self . counters_seen . contains ( id) ,
233
- CovTerm :: Expression ( id) => zero_expressions. contains ( id) ,
237
+ CovTerm :: Expression ( id) => self . zero_expressions . contains ( id) ,
234
238
CovTerm :: Zero => false ,
235
239
} ;
236
240
if force_to_zero { Counter :: ZERO } else { Counter :: from_term ( term) }
0 commit comments