diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index e739c6d04e1..d3f69a66557 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -24,11 +24,12 @@ use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan}; use errors::registry::Registry; use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, CodeMapper}; use errors::DiagnosticId; -use errors::emitter::Emitter; +use errors::emitter::{Emitter, EmitterWriter}; use std::rc::Rc; use std::io::{self, Write}; use std::vec; +use std::sync::{Arc, Mutex}; use rustc_serialize::json::{as_json, as_pretty_json}; @@ -95,7 +96,7 @@ struct Diagnostic { spans: Vec, /// Associated diagnostic messages. children: Vec, - /// The message as rustc would render it. Currently this is always `None` + /// The message as rustc would render it. rendered: Option, } @@ -170,6 +171,27 @@ impl Diagnostic { rendered: None, } }); + + // generate regular command line output and store it in the json + + // A threadsafe buffer for writing. + #[derive(Default, Clone)] + struct BufWriter(Arc>>); + + impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.lock().unwrap().write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.0.lock().unwrap().flush() + } + } + let buf = BufWriter::default(); + let output = buf.clone(); + EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false).emit(db); + let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); + let output = String::from_utf8(output).unwrap(); + Diagnostic { message: db.message(), code: DiagnosticCode::map_opt_string(db.code.clone(), je), @@ -178,7 +200,7 @@ impl Diagnostic { children: db.children.iter().map(|c| { Diagnostic::from_sub_diagnostic(c, je) }).chain(sugg).collect(), - rendered: None, + rendered: Some(output.to_owned()), } } diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index e166f7011b5..fe113eda3dd 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -87,5 +87,17 @@ "rendered": null } ], - "rendered": null + "rendered": "warning: unnecessary parentheses around assigned value + --> $DIR/unused_parens_json_suggestion.rs:24:14 + | +24 | let _a = (1 / (2 + 3)); + | ^^^^^^^^^^^^^ help: remove these parentheses + | +note: lint level defined here + --> $DIR/unused_parens_json_suggestion.rs:19:9 + | +19 | #![warn(unused_parens)] + | ^^^^^^^^^^^^^ + +" } diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index fd3b5fe1ada..d716dd53b97 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -2,7 +2,72 @@ "message": "cannot find type `Iter` in this scope", "code": { "code": "E0412", - "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(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" + "explanation": " +The type name used is not in scope. + +Erroneous code examples: + +```compile_fail,E0412 +impl Something {} // error: type name `Something` is not in scope + +// or: + +trait Foo { + fn bar(N); // error: type name `N` is not in scope +} + +// or: + +fn foo(x: T) {} // type name `T` is not in scope +``` + +To fix this error, please verify you didn't misspell the type name, you did +declare it or imported it into the scope. Examples: + +``` +struct Something; + +impl Something {} // ok! + +// or: + +trait Foo { + type N; + + fn bar(_: Self::N); // ok! +} + +// or: + +fn foo(x: T) {} // ok! +``` + +Another case that causes this error is when a type is imported into a parent +module. To fix this, you can follow the suggestion and use File directly or +`use super::File;` which will import the types from the parent namespace. An +example that causes this error is below: + +```compile_fail,E0412 +use std::fs::File; + +mod foo { + fn some_function(f: File) {} +} +``` + +``` +use std::fs::File; + +mod foo { + // either + use super::File; + // or + // use std::fs::File; + fn foo(f: File) {} +} +# fn main() {} // don't insert it for us; that'll break imports +``` +" }, "level": "error", "spans": [ @@ -50,7 +115,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::binary_heap::Iter;/n/n", + "suggested_replacement": "use std::collections::binary_heap::Iter; + +", "expansion": null }, { @@ -70,7 +137,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::btree_map::Iter;/n/n", + "suggested_replacement": "use std::collections::btree_map::Iter; + +", "expansion": null }, { @@ -90,7 +159,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::btree_set::Iter;/n/n", + "suggested_replacement": "use std::collections::btree_set::Iter; + +", "expansion": null }, { @@ -110,7 +181,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::hash_map::Iter;/n/n", + "suggested_replacement": "use std::collections::hash_map::Iter; + +", "expansion": null }, { @@ -130,7 +203,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::hash_set::Iter;/n/n", + "suggested_replacement": "use std::collections::hash_set::Iter; + +", "expansion": null }, { @@ -150,7 +225,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::linked_list::Iter;/n/n", + "suggested_replacement": "use std::collections::linked_list::Iter; + +", "expansion": null }, { @@ -170,7 +247,9 @@ } ], "label": null, - "suggested_replacement": "use std::collections::vec_deque::Iter;/n/n", + "suggested_replacement": "use std::collections::vec_deque::Iter; + +", "expansion": null }, { @@ -190,7 +269,9 @@ } ], "label": null, - "suggested_replacement": "use std::option::Iter;/n/n", + "suggested_replacement": "use std::option::Iter; + +", "expansion": null }, { @@ -210,7 +291,9 @@ } ], "label": null, - "suggested_replacement": "use std::path::Iter;/n/n", + "suggested_replacement": "use std::path::Iter; + +", "expansion": null }, { @@ -230,7 +313,9 @@ } ], "label": null, - "suggested_replacement": "use std::result::Iter;/n/n", + "suggested_replacement": "use std::result::Iter; + +", "expansion": null }, { @@ -250,7 +335,9 @@ } ], "label": null, - "suggested_replacement": "use std::slice::Iter;/n/n", + "suggested_replacement": "use std::slice::Iter; + +", "expansion": null }, { @@ -270,7 +357,9 @@ } ], "label": null, - "suggested_replacement": "use std::sync::mpsc::Iter;/n/n", + "suggested_replacement": "use std::sync::mpsc::Iter; + +", "expansion": null } ], @@ -278,7 +367,25 @@ "rendered": null } ], - "rendered": null + "rendered": "error[E0412]: cannot find type `Iter` in this scope + --> $DIR/use_suggestion_json.rs:20:12 + | +20 | let x: Iter; + | ^^^^ not found in this scope + | +help: possible candidates are found in other modules, you can import them into scope + | +19 | use std::collections::binary_heap::Iter; + | +19 | use std::collections::btree_map::Iter; + | +19 | use std::collections::btree_set::Iter; + | +19 | use std::collections::hash_map::Iter; + | +and 8 other candidates + +" } { "message": "aborting due to previous error", @@ -286,5 +393,7 @@ "level": "error", "spans": [], "children": [], - "rendered": null + "rendered": "error: aborting due to previous error + +" } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index b5a8a15b1a8..b74867aba2d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2400,15 +2400,21 @@ actual:\n\ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { let parent_dir = self.testpaths.file.parent().unwrap(); let cflags = self.props.compile_flags.join(" "); - let parent_dir_str = if cflags.contains("--error-format json") - || cflags.contains("--error-format pretty-json") { + let json = cflags.contains("--error-format json") || + cflags.contains("--error-format pretty-json"); + let parent_dir_str = if json { parent_dir.display().to_string().replace("\\", "\\\\") } else { parent_dir.display().to_string() }; - let mut normalized = output.replace(&parent_dir_str, "$DIR") - .replace("\\\\", "\\") // denormalize for paths on windows + let mut normalized = output.replace(&parent_dir_str, "$DIR"); + + if json { + normalized = normalized.replace("\\n", "\n"); // verbatim newline in json strings + } + + normalized = normalized.replace("\\\\", "\\") // denormalize for paths on windows .replace("\\", "/") // normalize for paths on windows .replace("\r\n", "\n") // normalize for linebreaks on windows .replace("\t", "\\t"); // makes tabs visible