11//! These structs are a subset of the ones found in `rustc_errors::json`.
22
33use std:: path:: { Path , PathBuf } ;
4- use std:: str:: FromStr ;
54use std:: sync:: OnceLock ;
65
76use regex:: Regex ;
@@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
142141}
143142
144143pub 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 (
165156 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: {}" ,
168158 error, line, output
169159 ) ) ,
170160 || ( ) ,
171161 ) ;
162+ }
172163 }
173164 }
174165 }
175- } else {
176- vec ! [ ]
177166 }
167+ errors
178168}
179169
180- fn push_expected_errors (
181- expected_errors : & mut Vec < Error > ,
170+ fn push_actual_errors (
171+ errors : & mut Vec < Error > ,
182172 diagnostic : & Diagnostic ,
183173 default_spans : & [ & DiagnosticSpan ] ,
184174 file_name : & str ,
@@ -236,44 +226,47 @@ fn push_expected_errors(
236226 }
237227 } ;
238228
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.
242231 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+ } ) ;
262253 }
263254 }
264255 for next_line in message_lines {
265256 if primary_spans. is_empty ( ) {
266- expected_errors . push ( Error {
257+ errors . push ( Error {
267258 line_num : None ,
268- kind : None ,
259+ kind,
269260 msg : with_code ( None , next_line) ,
261+ require_annotation : false ,
270262 } ) ;
271263 } else {
272264 for span in primary_spans {
273- expected_errors . push ( Error {
265+ errors . push ( Error {
274266 line_num : Some ( span. line_start ) ,
275- kind : None ,
267+ kind,
276268 msg : with_code ( Some ( span) , next_line) ,
269+ require_annotation : false ,
277270 } ) ;
278271 }
279272 }
@@ -283,10 +276,11 @@ fn push_expected_errors(
283276 for span in primary_spans {
284277 if let Some ( ref suggested_replacement) = span. suggested_replacement {
285278 for ( index, line) in suggested_replacement. lines ( ) . enumerate ( ) {
286- expected_errors . push ( Error {
279+ errors . push ( Error {
287280 line_num : Some ( span. line_start + index) ,
288281 kind : Some ( ErrorKind :: Suggestion ) ,
289282 msg : line. to_string ( ) ,
283+ require_annotation : true ,
290284 } ) ;
291285 }
292286 }
@@ -295,39 +289,41 @@ fn push_expected_errors(
295289 // Add notes for the backtrace
296290 for span in primary_spans {
297291 if let Some ( frame) = & span. expansion {
298- push_backtrace ( expected_errors , frame, file_name) ;
292+ push_backtrace ( errors , frame, file_name) ;
299293 }
300294 }
301295
302296 // Add notes for any labels that appear in the message.
303297 for span in spans_in_this_file. iter ( ) . filter ( |span| span. label . is_some ( ) ) {
304- expected_errors . push ( Error {
298+ errors . push ( Error {
305299 line_num : Some ( span. line_start ) ,
306300 kind : Some ( ErrorKind :: Note ) ,
307301 msg : span. label . clone ( ) . unwrap ( ) ,
302+ require_annotation : true ,
308303 } ) ;
309304 }
310305
311306 // Flatten out the children.
312307 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) ;
314309 }
315310}
316311
317312fn push_backtrace (
318- expected_errors : & mut Vec < Error > ,
313+ errors : & mut Vec < Error > ,
319314 expansion : & DiagnosticSpanMacroExpansion ,
320315 file_name : & str ,
321316) {
322317 if Path :: new ( & expansion. span . file_name ) == Path :: new ( & file_name) {
323- expected_errors . push ( Error {
318+ errors . push ( Error {
324319 line_num : Some ( expansion. span . line_start ) ,
325320 kind : Some ( ErrorKind :: Note ) ,
326321 msg : format ! ( "in this expansion of {}" , expansion. macro_decl_name) ,
322+ require_annotation : true ,
327323 } ) ;
328324 }
329325
330326 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) ;
332328 }
333329}
0 commit comments