about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2017-11-22 01:12:59 +0800
committerGitHub <noreply@github.com>2017-11-22 01:12:59 +0800
commit0af67a4df0219d518ecba6711ff8ff6680a9a2ec (patch)
tree850fd666fcd77c62c2cdf792282e7bd106ef8ebc
parent9b090a026108fab89cfe5f39bfd3492597e76ad4 (diff)
parente7b2702172b91624406e8c90716a225e8ec1a299 (diff)
downloadrust-0af67a4df0219d518ecba6711ff8ff6680a9a2ec.tar.gz
rust-0af67a4df0219d518ecba6711ff8ff6680a9a2ec.zip
Rollup merge of #46052 - oli-obk:rendered_diagnostics_in_json, r=petrochenkov
Include rendered diagnostic in json

r? @petrochenkov
-rw-r--r--src/librustc_errors/snippet.rs2
-rw-r--r--src/libsyntax/json.rs28
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.stderr14
-rw-r--r--src/test/ui/lint/use_suggestion_json.stderr138
-rw-r--r--src/tools/compiletest/src/runtest.rs18
5 files changed, 176 insertions, 24 deletions
diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs
index b76036b22df..c2f4701999e 100644
--- a/src/librustc_errors/snippet.rs
+++ b/src/librustc_errors/snippet.rs
@@ -70,7 +70,7 @@ impl MultilineAnnotation {
 
     pub fn as_end(&self) -> Annotation {
         Annotation {
-            start_col: self.end_col - 1,
+            start_col: self.end_col.saturating_sub(1),
             end_col: self.end_col,
             is_primary: self.is_primary,
             label: self.label.clone(),
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index e739c6d04e1..80ac0cb4faf 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<DiagnosticSpan>,
     /// Associated diagnostic messages.
     children: Vec<Diagnostic>,
-    /// The message as rustc would render it. Currently this is always `None`
+    /// The message as rustc would render it.
     rendered: Option<String>,
 }
 
@@ -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<Mutex<Vec<u8>>>);
+
+        impl Write for BufWriter {
+            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+                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),
         }
     }
 
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..846d7df445d 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<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"
+    "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<T>(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,24 @@
       "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 +392,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 749d1f4c378..1fd48881ba2 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2424,15 +2424,25 @@ 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 {
+            // escaped newlines in json strings should be readable
+            // in the stderr files. There's no point int being correct,
+            // since only humans process the stderr files.
+            // Thus we just turn escaped newlines back into newlines.
+            normalized = normalized.replace("\\n", "\n");
+        }
+
+        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