@@ -18,13 +18,17 @@ mod output;
18
18
mod rustc;
19
19
mod util;
20
20
21
+ use std:: collections:: HashMap ;
21
22
use std:: fmt;
22
23
use std:: fs:: { copy, OpenOptions } ;
23
24
use std:: io;
24
25
use std:: process:: { exit, Command , ExitStatus , Stdio } ;
25
26
27
+ use tinyjson:: JsonValue ;
28
+
26
29
use crate :: options:: options;
27
30
use crate :: output:: { process_output, LineOutput } ;
31
+ use crate :: rustc:: ErrorFormat ;
28
32
29
33
#[ cfg( windows) ]
30
34
fn status_code ( status : ExitStatus , was_killed : bool ) -> i32 {
@@ -69,6 +73,48 @@ macro_rules! log {
69
73
} ;
70
74
}
71
75
76
+ fn json_warning ( line : & str ) -> JsonValue {
77
+ JsonValue :: Object ( HashMap :: from ( [
78
+ (
79
+ "$message_type" . to_string ( ) ,
80
+ JsonValue :: String ( "diagnostic" . to_string ( ) ) ,
81
+ ) ,
82
+ ( "message" . to_string ( ) , JsonValue :: String ( line. to_string ( ) ) ) ,
83
+ ( "code" . to_string ( ) , JsonValue :: Null ) ,
84
+ (
85
+ "level" . to_string ( ) ,
86
+ JsonValue :: String ( "warning" . to_string ( ) ) ,
87
+ ) ,
88
+ ( "spans" . to_string ( ) , JsonValue :: Array ( Vec :: new ( ) ) ) ,
89
+ ( "children" . to_string ( ) , JsonValue :: Array ( Vec :: new ( ) ) ) ,
90
+ ( "rendered" . to_string ( ) , JsonValue :: String ( line. to_string ( ) ) ) ,
91
+ ] ) )
92
+ }
93
+
94
+ fn process_line (
95
+ mut line : String ,
96
+ quit_on_rmeta : bool ,
97
+ format : ErrorFormat ,
98
+ metadata_emitted : & mut bool ,
99
+ ) -> Result < LineOutput , String > {
100
+ // LLVM can emit lines that look like the following, and these will be interspersed
101
+ // with the regular JSON output. Arguably, rustc should be fixed not to emit lines
102
+ // like these (or to convert them to JSON), but for now we convert them to JSON
103
+ // ourselves.
104
+ if line. contains ( "is not a recognized feature for this target (ignoring feature)" ) {
105
+ if let Ok ( json_str) = json_warning ( & line) . stringify ( ) {
106
+ line = json_str;
107
+ } else {
108
+ return Ok ( LineOutput :: Skip ) ;
109
+ }
110
+ }
111
+ if quit_on_rmeta {
112
+ rustc:: stop_on_rmeta_completion ( line, format, metadata_emitted)
113
+ } else {
114
+ rustc:: process_json ( line, format)
115
+ }
116
+ }
117
+
72
118
fn main ( ) -> Result < ( ) , ProcessWrapperError > {
73
119
let opts = options ( ) . map_err ( |e| ProcessWrapperError ( e. to_string ( ) ) ) ?;
74
120
@@ -135,13 +181,7 @@ fn main() -> Result<(), ProcessWrapperError> {
135
181
& mut child_stderr,
136
182
stderr. as_mut ( ) ,
137
183
output_file. as_mut ( ) ,
138
- move |line| {
139
- if quit_on_rmeta {
140
- rustc:: stop_on_rmeta_completion ( line, format, metadata_emitted)
141
- } else {
142
- rustc:: process_json ( line, format)
143
- }
144
- } ,
184
+ move |line| process_line ( line, quit_on_rmeta, format, metadata_emitted) ,
145
185
) ;
146
186
if me {
147
187
// If recv returns Ok(), a signal was sent in this channel so we should terminate the child process.
@@ -188,3 +228,141 @@ fn main() -> Result<(), ProcessWrapperError> {
188
228
189
229
exit ( code)
190
230
}
231
+
232
+ #[ cfg( test) ]
233
+ mod test {
234
+ use super :: * ;
235
+
236
+ fn parse_json ( json_str : & str ) -> Result < JsonValue , String > {
237
+ json_str. parse :: < JsonValue > ( ) . map_err ( |e| e. to_string ( ) )
238
+ }
239
+
240
+ #[ test]
241
+ fn test_process_line_diagnostic_json ( ) -> Result < ( ) , String > {
242
+ let mut metadata_emitted = false ;
243
+ let LineOutput :: Message ( msg) = process_line (
244
+ r#"
245
+ {
246
+ "$message_type": "diagnostic",
247
+ "rendered": "Diagnostic message"
248
+ }
249
+ "#
250
+ . to_string ( ) ,
251
+ false ,
252
+ ErrorFormat :: Json ,
253
+ & mut metadata_emitted,
254
+ ) ?
255
+ else {
256
+ return Err ( "Expected a LineOutput::Message" . to_string ( ) ) ;
257
+ } ;
258
+ assert_eq ! (
259
+ parse_json( & msg) ?,
260
+ parse_json(
261
+ r#"
262
+ {
263
+ "$message_type": "diagnostic",
264
+ "rendered": "Diagnostic message"
265
+ }
266
+ "#
267
+ ) ?
268
+ ) ;
269
+ Ok ( ( ) )
270
+ }
271
+
272
+ #[ test]
273
+ fn test_process_line_diagnostic_rendered ( ) -> Result < ( ) , String > {
274
+ let mut metadata_emitted = false ;
275
+ let LineOutput :: Message ( msg) = process_line (
276
+ r#"
277
+ {
278
+ "$message_type": "diagnostic",
279
+ "rendered": "Diagnostic message"
280
+ }
281
+ "#
282
+ . to_string ( ) ,
283
+ /*quit_on_rmeta=*/ false ,
284
+ ErrorFormat :: Rendered ,
285
+ & mut metadata_emitted,
286
+ ) ?
287
+ else {
288
+ return Err ( "Expected a LineOutput::Message" . to_string ( ) ) ;
289
+ } ;
290
+ assert_eq ! ( msg, "Diagnostic message" ) ;
291
+ Ok ( ( ) )
292
+ }
293
+
294
+ #[ test]
295
+ fn test_process_line_llvm_feature_warning ( ) -> Result < ( ) , String > {
296
+ let mut metadata_emitted = false ;
297
+ let LineOutput :: Message ( msg) = process_line (
298
+ "'+zaamo' is not a recognized feature for this target (ignoring feature)" . to_string ( ) ,
299
+ /*quit_on_rmeta=*/ false ,
300
+ ErrorFormat :: Json ,
301
+ & mut metadata_emitted,
302
+ ) ?
303
+ else {
304
+ return Err ( "Expected a LineOutput::Message" . to_string ( ) ) ;
305
+ } ;
306
+ assert_eq ! (
307
+ parse_json( & msg) ?,
308
+ parse_json(
309
+ r#"
310
+ {
311
+ "$message_type": "diagnostic",
312
+ "message": "'+zaamo' is not a recognized feature for this target (ignoring feature)",
313
+ "code": null,
314
+ "level": "warning",
315
+ "spans": [],
316
+ "children": [],
317
+ "rendered": "'+zaamo' is not a recognized feature for this target (ignoring feature)"
318
+ }
319
+ "#
320
+ ) ?
321
+ ) ;
322
+ Ok ( ( ) )
323
+ }
324
+
325
+ #[ test]
326
+ fn test_process_line_emit_link ( ) -> Result < ( ) , String > {
327
+ let mut metadata_emitted = false ;
328
+ assert ! ( matches!(
329
+ process_line(
330
+ r#"
331
+ {
332
+ "$message_type": "artifact",
333
+ "emit": "link"
334
+ }
335
+ "#
336
+ . to_string( ) ,
337
+ /*quit_on_rmeta=*/ true ,
338
+ ErrorFormat :: Rendered ,
339
+ & mut metadata_emitted,
340
+ ) ?,
341
+ LineOutput :: Skip
342
+ ) ) ;
343
+ assert ! ( !metadata_emitted) ;
344
+ Ok ( ( ) )
345
+ }
346
+
347
+ #[ test]
348
+ fn test_process_line_emit_metadata ( ) -> Result < ( ) , String > {
349
+ let mut metadata_emitted = false ;
350
+ assert ! ( matches!(
351
+ process_line(
352
+ r#"
353
+ {
354
+ "$message_type": "artifact",
355
+ "emit": "metadata"
356
+ }
357
+ "#
358
+ . to_string( ) ,
359
+ /*quit_on_rmeta=*/ true ,
360
+ ErrorFormat :: Rendered ,
361
+ & mut metadata_emitted,
362
+ ) ?,
363
+ LineOutput :: Terminate
364
+ ) ) ;
365
+ assert ! ( metadata_emitted) ;
366
+ Ok ( ( ) )
367
+ }
368
+ }
0 commit comments