1
1
//! These structs are a subset of the ones found in `rustc_errors::json`.
2
2
3
3
use std:: path:: { Path , PathBuf } ;
4
- use std:: str:: FromStr ;
5
4
use std:: sync:: OnceLock ;
6
5
7
6
use regex:: Regex ;
@@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
142
141
}
143
142
144
143
pub fn parse_output ( file_name : & str , output : & str , proc_res : & ProcRes ) -> Vec < Error > {
145
- output. lines ( ) . flat_map ( |line| parse_line ( file_name, line, output, proc_res) ) . collect ( )
146
- }
147
-
148
- fn parse_line ( file_name : & str , line : & str , output : & str , proc_res : & ProcRes ) -> Vec < Error > {
149
- // The compiler sometimes intermingles non-JSON stuff into the
150
- // output. This hack just skips over such lines. Yuck.
151
- if line. starts_with ( '{' ) {
152
- match serde_json:: from_str :: < Diagnostic > ( line) {
153
- Ok ( diagnostic) => {
154
- let mut expected_errors = vec ! [ ] ;
155
- push_expected_errors ( & mut expected_errors, & diagnostic, & [ ] , file_name) ;
156
- expected_errors
157
- }
158
- Err ( error) => {
159
- // Ignore the future compat report message - this is handled
160
- // by `extract_rendered`
161
- if serde_json:: from_str :: < FutureIncompatReport > ( line) . is_ok ( ) {
162
- vec ! [ ]
163
- } else {
164
- proc_res. fatal (
144
+ let mut errors = Vec :: new ( ) ;
145
+ for line in output. lines ( ) {
146
+ // The compiler sometimes intermingles non-JSON stuff into the
147
+ // output. This hack just skips over such lines. Yuck.
148
+ if line. starts_with ( '{' ) {
149
+ match serde_json:: from_str :: < Diagnostic > ( line) {
150
+ Ok ( diagnostic) => push_actual_errors ( & mut errors, & diagnostic, & [ ] , file_name) ,
151
+ Err ( error) => {
152
+ // Ignore the future compat report message - this is handled
153
+ // by `extract_rendered`
154
+ if serde_json:: from_str :: < FutureIncompatReport > ( line) . is_err ( ) {
155
+ proc_res. fatal (
165
156
Some ( & format ! (
166
- "failed to decode compiler output as json: \
167
- `{}`\n line: {}\n output: {}",
157
+ "failed to decode compiler output as json: `{}`\n line: {}\n output: {}" ,
168
158
error, line, output
169
159
) ) ,
170
160
|| ( ) ,
171
161
) ;
162
+ }
172
163
}
173
164
}
174
165
}
175
- } else {
176
- vec ! [ ]
177
166
}
167
+ errors
178
168
}
179
169
180
- fn push_expected_errors (
181
- expected_errors : & mut Vec < Error > ,
170
+ fn push_actual_errors (
171
+ errors : & mut Vec < Error > ,
182
172
diagnostic : & Diagnostic ,
183
173
default_spans : & [ & DiagnosticSpan ] ,
184
174
file_name : & str ,
@@ -236,44 +226,47 @@ fn push_expected_errors(
236
226
}
237
227
} ;
238
228
239
- // Convert multi-line messages into multiple expected
240
- // errors. We expect to replace these with something
241
- // more structured shortly anyhow.
229
+ // Convert multi-line messages into multiple errors.
230
+ // We expect to replace these with something more structured anyhow.
242
231
let mut message_lines = diagnostic. message . lines ( ) ;
243
- if let Some ( first_line) = message_lines. next ( ) {
244
- let ignore = |s| {
245
- static RE : OnceLock < Regex > = OnceLock :: new ( ) ;
246
- RE . get_or_init ( || {
247
- Regex :: new ( r"aborting due to \d+ previous errors?|\d+ warnings? emitted" ) . unwrap ( )
248
- } )
249
- . is_match ( s)
250
- } ;
251
-
252
- if primary_spans. is_empty ( ) && !ignore ( first_line) {
253
- let msg = with_code ( None , first_line) ;
254
- let kind = ErrorKind :: from_str ( & diagnostic. level ) . ok ( ) ;
255
- expected_errors. push ( Error { line_num : None , kind, msg } ) ;
256
- } else {
257
- for span in primary_spans {
258
- let msg = with_code ( Some ( span) , first_line) ;
259
- let kind = ErrorKind :: from_str ( & diagnostic. level ) . ok ( ) ;
260
- expected_errors. push ( Error { line_num : Some ( span. line_start ) , kind, msg } ) ;
261
- }
232
+ let kind = Some ( ErrorKind :: from_compiler_str ( & diagnostic. level ) ) ;
233
+ let first_line = message_lines. next ( ) . unwrap_or ( & diagnostic. message ) ;
234
+ if primary_spans. is_empty ( ) {
235
+ static RE : OnceLock < Regex > = OnceLock :: new ( ) ;
236
+ let re_init =
237
+ || Regex :: new ( r"aborting due to \d+ previous errors?|\d+ warnings? emitted" ) . unwrap ( ) ;
238
+ errors. push ( Error {
239
+ line_num : None ,
240
+ kind,
241
+ msg : with_code ( None , first_line) ,
242
+ require_annotation : diagnostic. level != "failure-note"
243
+ && !RE . get_or_init ( re_init) . is_match ( first_line) ,
244
+ } ) ;
245
+ } else {
246
+ for span in primary_spans {
247
+ errors. push ( Error {
248
+ line_num : Some ( span. line_start ) ,
249
+ kind,
250
+ msg : with_code ( Some ( span) , first_line) ,
251
+ require_annotation : true ,
252
+ } ) ;
262
253
}
263
254
}
264
255
for next_line in message_lines {
265
256
if primary_spans. is_empty ( ) {
266
- expected_errors . push ( Error {
257
+ errors . push ( Error {
267
258
line_num : None ,
268
- kind : None ,
259
+ kind,
269
260
msg : with_code ( None , next_line) ,
261
+ require_annotation : false ,
270
262
} ) ;
271
263
} else {
272
264
for span in primary_spans {
273
- expected_errors . push ( Error {
265
+ errors . push ( Error {
274
266
line_num : Some ( span. line_start ) ,
275
- kind : None ,
267
+ kind,
276
268
msg : with_code ( Some ( span) , next_line) ,
269
+ require_annotation : false ,
277
270
} ) ;
278
271
}
279
272
}
@@ -283,10 +276,11 @@ fn push_expected_errors(
283
276
for span in primary_spans {
284
277
if let Some ( ref suggested_replacement) = span. suggested_replacement {
285
278
for ( index, line) in suggested_replacement. lines ( ) . enumerate ( ) {
286
- expected_errors . push ( Error {
279
+ errors . push ( Error {
287
280
line_num : Some ( span. line_start + index) ,
288
281
kind : Some ( ErrorKind :: Suggestion ) ,
289
282
msg : line. to_string ( ) ,
283
+ require_annotation : true ,
290
284
} ) ;
291
285
}
292
286
}
@@ -295,39 +289,41 @@ fn push_expected_errors(
295
289
// Add notes for the backtrace
296
290
for span in primary_spans {
297
291
if let Some ( frame) = & span. expansion {
298
- push_backtrace ( expected_errors , frame, file_name) ;
292
+ push_backtrace ( errors , frame, file_name) ;
299
293
}
300
294
}
301
295
302
296
// Add notes for any labels that appear in the message.
303
297
for span in spans_in_this_file. iter ( ) . filter ( |span| span. label . is_some ( ) ) {
304
- expected_errors . push ( Error {
298
+ errors . push ( Error {
305
299
line_num : Some ( span. line_start ) ,
306
300
kind : Some ( ErrorKind :: Note ) ,
307
301
msg : span. label . clone ( ) . unwrap ( ) ,
302
+ require_annotation : true ,
308
303
} ) ;
309
304
}
310
305
311
306
// Flatten out the children.
312
307
for child in & diagnostic. children {
313
- push_expected_errors ( expected_errors , child, primary_spans, file_name) ;
308
+ push_actual_errors ( errors , child, primary_spans, file_name) ;
314
309
}
315
310
}
316
311
317
312
fn push_backtrace (
318
- expected_errors : & mut Vec < Error > ,
313
+ errors : & mut Vec < Error > ,
319
314
expansion : & DiagnosticSpanMacroExpansion ,
320
315
file_name : & str ,
321
316
) {
322
317
if Path :: new ( & expansion. span . file_name ) == Path :: new ( & file_name) {
323
- expected_errors . push ( Error {
318
+ errors . push ( Error {
324
319
line_num : Some ( expansion. span . line_start ) ,
325
320
kind : Some ( ErrorKind :: Note ) ,
326
321
msg : format ! ( "in this expansion of {}" , expansion. macro_decl_name) ,
322
+ require_annotation : true ,
327
323
} ) ;
328
324
}
329
325
330
326
if let Some ( previous_expansion) = & expansion. span . expansion {
331
- push_backtrace ( expected_errors , previous_expansion, file_name) ;
327
+ push_backtrace ( errors , previous_expansion, file_name) ;
332
328
}
333
329
}
0 commit comments