@@ -3,12 +3,8 @@ pub use super::ffi::*;
3
3
use rustc_index:: vec:: IndexVec ;
4
4
use rustc_middle:: ty:: Instance ;
5
5
use rustc_middle:: ty:: TyCtxt ;
6
- use rustc_span:: source_map:: { Pos , SourceMap } ;
7
- use rustc_span:: { BytePos , FileName , Loc , RealFileName } ;
8
6
9
- use std:: cmp:: { Ord , Ordering } ;
10
- use std:: fmt;
11
- use std:: path:: PathBuf ;
7
+ use std:: cmp:: Ord ;
12
8
13
9
rustc_index:: newtype_index! {
14
10
pub struct ExpressionOperandId {
@@ -38,127 +34,35 @@ rustc_index::newtype_index! {
38
34
}
39
35
}
40
36
41
- #[ derive( Clone , Debug ) ]
42
- pub struct Region {
43
- start : Loc ,
44
- end : Loc ,
45
- }
46
-
47
- impl Ord for Region {
48
- fn cmp ( & self , other : & Self ) -> Ordering {
49
- ( & self . start . file . name , & self . start . line , & self . start . col , & self . end . line , & self . end . col )
50
- . cmp ( & (
51
- & other. start . file . name ,
52
- & other. start . line ,
53
- & other. start . col ,
54
- & other. end . line ,
55
- & other. end . col ,
56
- ) )
57
- }
58
- }
59
-
60
- impl PartialOrd for Region {
61
- fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
62
- Some ( self . cmp ( other) )
63
- }
64
- }
65
-
66
- impl PartialEq for Region {
67
- fn eq ( & self , other : & Self ) -> bool {
68
- self . start . file . name == other. start . file . name
69
- && self . start . line == other. start . line
70
- && self . start . col == other. start . col
71
- && self . end . line == other. end . line
72
- && self . end . col == other. end . col
73
- }
74
- }
75
-
76
- impl Eq for Region { }
77
-
78
- impl fmt:: Display for Region {
79
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
80
- let ( file_path, start_line, start_col, end_line, end_col) = self . file_start_and_end ( ) ;
81
- write ! ( f, "{:?}:{}:{} - {}:{}" , file_path, start_line, start_col, end_line, end_col)
82
- }
37
+ #[ derive( Clone , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
38
+ pub struct Region < ' tcx > {
39
+ pub file_name : & ' tcx str ,
40
+ pub start_line : u32 ,
41
+ pub start_col : u32 ,
42
+ pub end_line : u32 ,
43
+ pub end_col : u32 ,
83
44
}
84
45
85
- impl Region {
86
- pub fn new ( source_map : & SourceMap , start_byte_pos : u32 , end_byte_pos : u32 ) -> Self {
87
- let start = source_map. lookup_char_pos ( BytePos :: from_u32 ( start_byte_pos) ) ;
88
- let end = source_map. lookup_char_pos ( BytePos :: from_u32 ( end_byte_pos) ) ;
89
- assert_eq ! (
90
- start. file. name, end. file. name,
91
- "Region start ({} -> {:?}) and end ({} -> {:?}) don't come from the same source file!" ,
92
- start_byte_pos, start, end_byte_pos, end
93
- ) ;
94
- Self { start, end }
95
- }
96
-
97
- pub fn file_start_and_end < ' a > ( & ' a self ) -> ( & ' a PathBuf , u32 , u32 , u32 , u32 ) {
98
- let start = & self . start ;
99
- let end = & self . end ;
100
- match & start. file . name {
101
- FileName :: Real ( RealFileName :: Named ( path) ) => (
102
- path,
103
- start. line as u32 ,
104
- start. col . to_u32 ( ) + 1 ,
105
- end. line as u32 ,
106
- end. col . to_u32 ( ) + 1 ,
107
- ) ,
108
- _ => {
109
- bug ! ( "start.file.name should be a RealFileName, but it was: {:?}" , start. file. name)
110
- }
111
- }
46
+ impl < ' tcx > Region < ' tcx > {
47
+ pub fn new (
48
+ file_name : & ' tcx str ,
49
+ start_line : u32 ,
50
+ start_col : u32 ,
51
+ end_line : u32 ,
52
+ end_col : u32 ,
53
+ ) -> Self {
54
+ Self { file_name, start_line, start_col, end_line, end_col }
112
55
}
113
56
}
114
57
115
58
#[ derive( Clone , Debug ) ]
116
- pub struct ExpressionRegion {
59
+ pub struct ExpressionRegion < ' tcx > {
117
60
lhs : ExpressionOperandId ,
118
61
op : ExprKind ,
119
62
rhs : ExpressionOperandId ,
120
- region : Region ,
63
+ region : Region < ' tcx > ,
121
64
}
122
65
123
- // FIXME(richkadel): There seems to be a problem computing the file location in
124
- // some cases. I need to investigate this more. When I generate and show coverage
125
- // for the example binary in the crates.io crate `json5format`, I had a couple of
126
- // notable problems:
127
- //
128
- // 1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in
129
- // various comments (not corresponding to rustdoc code), indicating a possible
130
- // problem with the byte_pos-to-source-map implementation.
131
- //
132
- // 2. And (perhaps not related) when I build the aforementioned example binary with:
133
- // `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`
134
- // and then run that binary with
135
- // `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \
136
- // some.json5` for some reason the binary generates *TWO* `.profraw` files. One
137
- // named `default.profraw` and the other named `formatjson5.profraw` (the expected
138
- // name, in this case).
139
- //
140
- // 3. I think that if I eliminate regions within a function, their region_ids,
141
- // referenced in expressions, will be wrong? I think the ids are implied by their
142
- // array position in the final coverage map output (IIRC).
143
- //
144
- // 4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some
145
- // region start/end byte positions. Just like I couldn't get the function hash at
146
- // intrinsic codegen time for external crate functions, I think the SourceMap I
147
- // have here only applies to the local crate, and I know I have coverages that
148
- // reference external crates.
149
- //
150
- // I still don't know if I fixed the hash problem correctly. If external crates
151
- // implement the function, can't I use the coverage counters already compiled
152
- // into those external crates? (Maybe not for generics and/or maybe not for
153
- // macros... not sure. But I need to understand this better.)
154
- //
155
- // If the byte range conversion is wrong, fix it. But if it
156
- // is right, then it is possible for the start and end to be in different files.
157
- // Can I do something other than ignore coverages that span multiple files?
158
- //
159
- // If I can resolve this, remove the "Option<>" result type wrapper
160
- // `regions_in_file_order()` accordingly.
161
-
162
66
/// Collects all of the coverage regions associated with (a) injected counters, (b) counter
163
67
/// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
164
68
/// for a given Function. Counters and counter expressions have non-overlapping `id`s because they
@@ -171,19 +75,17 @@ pub struct ExpressionRegion {
171
75
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
172
76
/// for a gap area is only used as the line execution count if there are no other regions on a
173
77
/// line."
174
- pub struct FunctionCoverage < ' a > {
175
- source_map : & ' a SourceMap ,
78
+ pub struct FunctionCoverage < ' tcx > {
176
79
source_hash : u64 ,
177
- counters : IndexVec < CounterValueReference , Option < Region > > ,
178
- expressions : IndexVec < InjectedExpressionIndex , Option < ExpressionRegion > > ,
179
- unreachable_regions : Vec < Region > ,
80
+ counters : IndexVec < CounterValueReference , Option < Region < ' tcx > > > ,
81
+ expressions : IndexVec < InjectedExpressionIndex , Option < ExpressionRegion < ' tcx > > > ,
82
+ unreachable_regions : Vec < Region < ' tcx > > ,
180
83
}
181
84
182
- impl < ' a > FunctionCoverage < ' a > {
183
- pub fn new < ' tcx : ' a > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
85
+ impl < ' tcx > FunctionCoverage < ' tcx > {
86
+ pub fn new ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
184
87
let coverageinfo = tcx. coverageinfo ( instance. def_id ( ) ) ;
185
88
Self {
186
- source_map : tcx. sess . source_map ( ) ,
187
89
source_hash : 0 , // will be set with the first `add_counter()`
188
90
counters : IndexVec :: from_elem_n ( None , coverageinfo. num_counters as usize ) ,
189
91
expressions : IndexVec :: from_elem_n ( None , coverageinfo. num_expressions as usize ) ,
@@ -194,20 +96,14 @@ impl<'a> FunctionCoverage<'a> {
194
96
/// Adds a code region to be counted by an injected counter intrinsic.
195
97
/// The source_hash (computed during coverage instrumentation) should also be provided, and
196
98
/// should be the same for all counters in a given function.
197
- pub fn add_counter (
198
- & mut self ,
199
- source_hash : u64 ,
200
- id : u32 ,
201
- start_byte_pos : u32 ,
202
- end_byte_pos : u32 ,
203
- ) {
99
+ pub fn add_counter ( & mut self , source_hash : u64 , id : u32 , region : Region < ' tcx > ) {
204
100
if self . source_hash == 0 {
205
101
self . source_hash = source_hash;
206
102
} else {
207
103
debug_assert_eq ! ( source_hash, self . source_hash) ;
208
104
}
209
105
self . counters [ CounterValueReference :: from ( id) ]
210
- . replace ( Region :: new ( self . source_map , start_byte_pos , end_byte_pos ) )
106
+ . replace ( region )
211
107
. expect_none ( "add_counter called with duplicate `id`" ) ;
212
108
}
213
109
@@ -231,27 +127,21 @@ impl<'a> FunctionCoverage<'a> {
231
127
lhs : u32 ,
232
128
op : ExprKind ,
233
129
rhs : u32 ,
234
- start_byte_pos : u32 ,
235
- end_byte_pos : u32 ,
130
+ region : Region < ' tcx > ,
236
131
) {
237
132
let expression_id = ExpressionOperandId :: from ( id_descending_from_max) ;
238
133
let lhs = ExpressionOperandId :: from ( lhs) ;
239
134
let rhs = ExpressionOperandId :: from ( rhs) ;
240
135
241
136
let expression_index = self . expression_index ( expression_id) ;
242
137
self . expressions [ expression_index]
243
- . replace ( ExpressionRegion {
244
- lhs,
245
- op,
246
- rhs,
247
- region : Region :: new ( self . source_map , start_byte_pos, end_byte_pos) ,
248
- } )
138
+ . replace ( ExpressionRegion { lhs, op, rhs, region } )
249
139
. expect_none ( "add_counter_expression called with duplicate `id_descending_from_max`" ) ;
250
140
}
251
141
252
142
/// Add a region that will be marked as "unreachable", with a constant "zero counter".
253
- pub fn add_unreachable_region ( & mut self , start_byte_pos : u32 , end_byte_pos : u32 ) {
254
- self . unreachable_regions . push ( Region :: new ( self . source_map , start_byte_pos , end_byte_pos ) ) ;
143
+ pub fn add_unreachable_region ( & mut self , region : Region < ' tcx > ) {
144
+ self . unreachable_regions . push ( region )
255
145
}
256
146
257
147
/// Return the source hash, generated from the HIR node structure, and used to indicate whether
@@ -264,8 +154,8 @@ impl<'a> FunctionCoverage<'a> {
264
154
/// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
265
155
/// `CounterMappingRegion`s.
266
156
pub fn get_expressions_and_counter_regions (
267
- & ' a self ,
268
- ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' a Region ) > ) {
157
+ & ' tcx self ,
158
+ ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' tcx Region < ' tcx > ) > ) {
269
159
assert ! ( self . source_hash != 0 ) ;
270
160
271
161
let counter_regions = self . counter_regions ( ) ;
@@ -277,7 +167,7 @@ impl<'a> FunctionCoverage<'a> {
277
167
( counter_expressions, counter_regions)
278
168
}
279
169
280
- fn counter_regions ( & ' a self ) -> impl Iterator < Item = ( Counter , & ' a Region ) > {
170
+ fn counter_regions ( & ' tcx self ) -> impl Iterator < Item = ( Counter , & ' tcx Region < ' tcx > ) > {
281
171
self . counters . iter_enumerated ( ) . filter_map ( |( index, entry) | {
282
172
// Option::map() will return None to filter out missing counters. This may happen
283
173
// if, for example, a MIR-instrumented counter is removed during an optimization.
@@ -288,8 +178,8 @@ impl<'a> FunctionCoverage<'a> {
288
178
}
289
179
290
180
fn expressions_with_regions (
291
- & ' a self ,
292
- ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' a Region ) > ) {
181
+ & ' tcx self ,
182
+ ) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' tcx Region < ' tcx > ) > ) {
293
183
let mut counter_expressions = Vec :: with_capacity ( self . expressions . len ( ) ) ;
294
184
let mut expression_regions = Vec :: with_capacity ( self . expressions . len ( ) ) ;
295
185
let mut new_indexes =
@@ -350,7 +240,7 @@ impl<'a> FunctionCoverage<'a> {
350
240
( counter_expressions, expression_regions. into_iter ( ) )
351
241
}
352
242
353
- fn unreachable_regions ( & ' a self ) -> impl Iterator < Item = ( Counter , & ' a Region ) > {
243
+ fn unreachable_regions ( & ' tcx self ) -> impl Iterator < Item = ( Counter , & ' tcx Region < ' tcx > ) > {
354
244
self . unreachable_regions . iter ( ) . map ( |region| ( Counter :: zero ( ) , region) )
355
245
}
356
246
0 commit comments