Skip to content

Commit 0af67a4

Browse files
authored
Rollup merge of rust-lang#46052 - oli-obk:rendered_diagnostics_in_json, r=petrochenkov
Include rendered diagnostic in json r? @petrochenkov
2 parents 9b090a0 + e7b2702 commit 0af67a4

File tree

5 files changed

+176
-24
lines changed

5 files changed

+176
-24
lines changed

src/librustc_errors/snippet.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl MultilineAnnotation {
7070

7171
pub fn as_end(&self) -> Annotation {
7272
Annotation {
73-
start_col: self.end_col - 1,
73+
start_col: self.end_col.saturating_sub(1),
7474
end_col: self.end_col,
7575
is_primary: self.is_primary,
7676
label: self.label.clone(),

src/libsyntax/json.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
2424
use errors::registry::Registry;
2525
use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, CodeMapper};
2626
use errors::DiagnosticId;
27-
use errors::emitter::Emitter;
27+
use errors::emitter::{Emitter, EmitterWriter};
2828

2929
use std::rc::Rc;
3030
use std::io::{self, Write};
3131
use std::vec;
32+
use std::sync::{Arc, Mutex};
3233

3334
use rustc_serialize::json::{as_json, as_pretty_json};
3435

@@ -95,7 +96,7 @@ struct Diagnostic {
9596
spans: Vec<DiagnosticSpan>,
9697
/// Associated diagnostic messages.
9798
children: Vec<Diagnostic>,
98-
/// The message as rustc would render it. Currently this is always `None`
99+
/// The message as rustc would render it.
99100
rendered: Option<String>,
100101
}
101102

@@ -170,6 +171,27 @@ impl Diagnostic {
170171
rendered: None,
171172
}
172173
});
174+
175+
// generate regular command line output and store it in the json
176+
177+
// A threadsafe buffer for writing.
178+
#[derive(Default, Clone)]
179+
struct BufWriter(Arc<Mutex<Vec<u8>>>);
180+
181+
impl Write for BufWriter {
182+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
183+
self.0.lock().unwrap().write(buf)
184+
}
185+
fn flush(&mut self) -> io::Result<()> {
186+
self.0.lock().unwrap().flush()
187+
}
188+
}
189+
let buf = BufWriter::default();
190+
let output = buf.clone();
191+
EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false).emit(db);
192+
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
193+
let output = String::from_utf8(output).unwrap();
194+
173195
Diagnostic {
174196
message: db.message(),
175197
code: DiagnosticCode::map_opt_string(db.code.clone(), je),
@@ -178,7 +200,7 @@ impl Diagnostic {
178200
children: db.children.iter().map(|c| {
179201
Diagnostic::from_sub_diagnostic(c, je)
180202
}).chain(sugg).collect(),
181-
rendered: None,
203+
rendered: Some(output),
182204
}
183205
}
184206

src/test/ui/lint/unused_parens_json_suggestion.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,17 @@
8787
"rendered": null
8888
}
8989
],
90-
"rendered": null
90+
"rendered": "warning: unnecessary parentheses around assigned value
91+
--> $DIR/unused_parens_json_suggestion.rs:24:14
92+
|
93+
24 | let _a = (1 / (2 + 3));
94+
| ^^^^^^^^^^^^^ help: remove these parentheses
95+
|
96+
note: lint level defined here
97+
--> $DIR/unused_parens_json_suggestion.rs:19:9
98+
|
99+
19 | #![warn(unused_parens)]
100+
| ^^^^^^^^^^^^^
101+
102+
"
91103
}

src/test/ui/lint/use_suggestion_json.stderr

Lines changed: 123 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,72 @@
22
"message": "cannot find type `Iter` in this scope",
33
"code": {
44
"code": "E0412",
5-
"explanation": "/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n type N;/n/n fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n // either/n use super::File;/n // or/n // use std::fs::File;/n fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n"
5+
"explanation": "
6+
The type name used is not in scope.
7+
8+
Erroneous code examples:
9+
10+
```compile_fail,E0412
11+
impl Something {} // error: type name `Something` is not in scope
12+
13+
// or:
14+
15+
trait Foo {
16+
fn bar(N); // error: type name `N` is not in scope
17+
}
18+
19+
// or:
20+
21+
fn foo(x: T) {} // type name `T` is not in scope
22+
```
23+
24+
To fix this error, please verify you didn't misspell the type name, you did
25+
declare it or imported it into the scope. Examples:
26+
27+
```
28+
struct Something;
29+
30+
impl Something {} // ok!
31+
32+
// or:
33+
34+
trait Foo {
35+
type N;
36+
37+
fn bar(_: Self::N); // ok!
38+
}
39+
40+
// or:
41+
42+
fn foo<T>(x: T) {} // ok!
43+
```
44+
45+
Another case that causes this error is when a type is imported into a parent
46+
module. To fix this, you can follow the suggestion and use File directly or
47+
`use super::File;` which will import the types from the parent namespace. An
48+
example that causes this error is below:
49+
50+
```compile_fail,E0412
51+
use std::fs::File;
52+
53+
mod foo {
54+
fn some_function(f: File) {}
55+
}
56+
```
57+
58+
```
59+
use std::fs::File;
60+
61+
mod foo {
62+
// either
63+
use super::File;
64+
// or
65+
// use std::fs::File;
66+
fn foo(f: File) {}
67+
}
68+
# fn main() {} // don't insert it for us; that'll break imports
69+
```
70+
"
671
},
772
"level": "error",
873
"spans": [
@@ -50,7 +115,9 @@
50115
}
51116
],
52117
"label": null,
53-
"suggested_replacement": "use std::collections::binary_heap::Iter;/n/n",
118+
"suggested_replacement": "use std::collections::binary_heap::Iter;
119+
120+
",
54121
"expansion": null
55122
},
56123
{
@@ -70,7 +137,9 @@
70137
}
71138
],
72139
"label": null,
73-
"suggested_replacement": "use std::collections::btree_map::Iter;/n/n",
140+
"suggested_replacement": "use std::collections::btree_map::Iter;
141+
142+
",
74143
"expansion": null
75144
},
76145
{
@@ -90,7 +159,9 @@
90159
}
91160
],
92161
"label": null,
93-
"suggested_replacement": "use std::collections::btree_set::Iter;/n/n",
162+
"suggested_replacement": "use std::collections::btree_set::Iter;
163+
164+
",
94165
"expansion": null
95166
},
96167
{
@@ -110,7 +181,9 @@
110181
}
111182
],
112183
"label": null,
113-
"suggested_replacement": "use std::collections::hash_map::Iter;/n/n",
184+
"suggested_replacement": "use std::collections::hash_map::Iter;
185+
186+
",
114187
"expansion": null
115188
},
116189
{
@@ -130,7 +203,9 @@
130203
}
131204
],
132205
"label": null,
133-
"suggested_replacement": "use std::collections::hash_set::Iter;/n/n",
206+
"suggested_replacement": "use std::collections::hash_set::Iter;
207+
208+
",
134209
"expansion": null
135210
},
136211
{
@@ -150,7 +225,9 @@
150225
}
151226
],
152227
"label": null,
153-
"suggested_replacement": "use std::collections::linked_list::Iter;/n/n",
228+
"suggested_replacement": "use std::collections::linked_list::Iter;
229+
230+
",
154231
"expansion": null
155232
},
156233
{
@@ -170,7 +247,9 @@
170247
}
171248
],
172249
"label": null,
173-
"suggested_replacement": "use std::collections::vec_deque::Iter;/n/n",
250+
"suggested_replacement": "use std::collections::vec_deque::Iter;
251+
252+
",
174253
"expansion": null
175254
},
176255
{
@@ -190,7 +269,9 @@
190269
}
191270
],
192271
"label": null,
193-
"suggested_replacement": "use std::option::Iter;/n/n",
272+
"suggested_replacement": "use std::option::Iter;
273+
274+
",
194275
"expansion": null
195276
},
196277
{
@@ -210,7 +291,9 @@
210291
}
211292
],
212293
"label": null,
213-
"suggested_replacement": "use std::path::Iter;/n/n",
294+
"suggested_replacement": "use std::path::Iter;
295+
296+
",
214297
"expansion": null
215298
},
216299
{
@@ -230,7 +313,9 @@
230313
}
231314
],
232315
"label": null,
233-
"suggested_replacement": "use std::result::Iter;/n/n",
316+
"suggested_replacement": "use std::result::Iter;
317+
318+
",
234319
"expansion": null
235320
},
236321
{
@@ -250,7 +335,9 @@
250335
}
251336
],
252337
"label": null,
253-
"suggested_replacement": "use std::slice::Iter;/n/n",
338+
"suggested_replacement": "use std::slice::Iter;
339+
340+
",
254341
"expansion": null
255342
},
256343
{
@@ -270,21 +357,42 @@
270357
}
271358
],
272359
"label": null,
273-
"suggested_replacement": "use std::sync::mpsc::Iter;/n/n",
360+
"suggested_replacement": "use std::sync::mpsc::Iter;
361+
362+
",
274363
"expansion": null
275364
}
276365
],
277366
"children": [],
278367
"rendered": null
279368
}
280369
],
281-
"rendered": null
370+
"rendered": "error[E0412]: cannot find type `Iter` in this scope
371+
--> $DIR/use_suggestion_json.rs:20:12
372+
|
373+
20 | let x: Iter;
374+
| ^^^^ not found in this scope
375+
help: possible candidates are found in other modules, you can import them into scope
376+
|
377+
19 | use std::collections::binary_heap::Iter;
378+
|
379+
19 | use std::collections::btree_map::Iter;
380+
|
381+
19 | use std::collections::btree_set::Iter;
382+
|
383+
19 | use std::collections::hash_map::Iter;
384+
|
385+
and 8 other candidates
386+
387+
"
282388
}
283389
{
284390
"message": "aborting due to previous error",
285391
"code": null,
286392
"level": "error",
287393
"spans": [],
288394
"children": [],
289-
"rendered": null
395+
"rendered": "error: aborting due to previous error
396+
397+
"
290398
}

src/tools/compiletest/src/runtest.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,15 +2424,25 @@ actual:\n\
24242424
fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
24252425
let parent_dir = self.testpaths.file.parent().unwrap();
24262426
let cflags = self.props.compile_flags.join(" ");
2427-
let parent_dir_str = if cflags.contains("--error-format json")
2428-
|| cflags.contains("--error-format pretty-json") {
2427+
let json = cflags.contains("--error-format json") ||
2428+
cflags.contains("--error-format pretty-json");
2429+
let parent_dir_str = if json {
24292430
parent_dir.display().to_string().replace("\\", "\\\\")
24302431
} else {
24312432
parent_dir.display().to_string()
24322433
};
24332434

2434-
let mut normalized = output.replace(&parent_dir_str, "$DIR")
2435-
.replace("\\\\", "\\") // denormalize for paths on windows
2435+
let mut normalized = output.replace(&parent_dir_str, "$DIR");
2436+
2437+
if json {
2438+
// escaped newlines in json strings should be readable
2439+
// in the stderr files. There's no point int being correct,
2440+
// since only humans process the stderr files.
2441+
// Thus we just turn escaped newlines back into newlines.
2442+
normalized = normalized.replace("\\n", "\n");
2443+
}
2444+
2445+
normalized = normalized.replace("\\\\", "\\") // denormalize for paths on windows
24362446
.replace("\\", "/") // normalize for paths on windows
24372447
.replace("\r\n", "\n") // normalize for linebreaks on windows
24382448
.replace("\t", "\\t"); // makes tabs visible

0 commit comments

Comments
 (0)