about summary refs log tree commit diff
path: root/src/librustc_errors
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-02-26 12:34:52 +0000
committerbors <bors@rust-lang.org>2018-02-26 12:34:52 +0000
commitbedbad61195d2eae69b43eca49c6d3e2aee8f208 (patch)
tree242925aa9132336b287d9bbbc2ab5f51d382369c /src/librustc_errors
parent4a70e272191862cdb7858a1b5b21cd811281d8db (diff)
parentce6429af7af295e41c3483838ea2f099e490c78f (diff)
Auto merge of #48337 - GuillaumeGomez:rustc-explain, r=estebank
Rustc explain

Fixes #48041.

To make the review easier, I separated tests update to code update. Also, I used this script to generate new ui tests stderr:

```python
from os import listdir
from os.path import isdir, isfile, join

PATH = "src/test/ui"

def do_something(path):
    files = [join(path, f) for f in listdir(path)]

    for f in files:
        if isdir(f):
            do_something(f)
            continue
        if not isfile(f) or not f.endswith(".stderr"):
            continue
        x = open(f, "r")
        content = x.read().strip()
        if "error[E" not in content:
            continue
        errors = dict()
        for y in content.splitlines():
            if y.startswith("error[E"):
                errors[y[6:11]] = True
        errors = sorted(errors.keys())
        if len(errors) < 1:
            print("weird... {}".format(f))
            continue
        if len(errors) > 1:
            content += "\n\nYou've got a few errors: {}".format(", ".join(errors))
            content += "\nIf you want more information on an error, try using \"rustc --explain {}\"".format(errors[0])
        else:
            content += "\n\nIf you want more information on this error, try using \"rustc --explain {}\"".format(errors[0])
        content += "\n"
        x = open(f, "w")
        x.write(content)

do_something(PATH)
```
Diffstat (limited to 'src/librustc_errors')
-rw-r--r--src/librustc_errors/emitter.rs53
1 files changed, 46 insertions, 7 deletions
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index a49284eb55a..86e77d404ff 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -21,7 +21,7 @@ use std::io::prelude::*;
 use std::io;
 use std::rc::Rc;
 use term;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::cmp::min;
 use unicode_width;
 
@@ -107,6 +107,7 @@ pub struct EmitterWriter {
     cm: Option<Rc<CodeMapper>>,
     short_message: bool,
     teach: bool,
+    error_codes: HashSet<String>,
 }
 
 struct FileWithAnnotatedLines {
@@ -115,6 +116,33 @@ struct FileWithAnnotatedLines {
     multiline_depth: usize,
 }
 
+impl Drop for EmitterWriter {
+    fn drop(&mut self) {
+        if !self.short_message && !self.error_codes.is_empty() {
+            let mut error_codes = self.error_codes.clone().into_iter().collect::<Vec<_>>();
+            error_codes.sort();
+            if error_codes.len() > 1 {
+                let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
+                writeln!(self.dst,
+                         "You've got a few errors: {}{}",
+                         error_codes[..limit].join(", "),
+                         if error_codes.len() > 9 { "..." } else { "" }
+                        ).expect("failed to give tips...");
+                writeln!(self.dst,
+                         "If you want more information on an error, try using \
+                          \"rustc --explain {}\"",
+                         &error_codes[0]).expect("failed to give tips...");
+            } else {
+                writeln!(self.dst,
+                         "If you want more information on this error, try using \
+                          \"rustc --explain {}\"",
+                         &error_codes[0]).expect("failed to give tips...");
+            }
+            self.dst.flush().expect("failed to emit errors");
+        }
+    }
+}
+
 impl EmitterWriter {
     pub fn stderr(color_config: ColorConfig,
                   code_map: Option<Rc<CodeMapper>>,
@@ -128,6 +156,7 @@ impl EmitterWriter {
                 cm: code_map,
                 short_message,
                 teach,
+                error_codes: HashSet::new(),
             }
         } else {
             EmitterWriter {
@@ -135,6 +164,7 @@ impl EmitterWriter {
                 cm: code_map,
                 short_message,
                 teach,
+                error_codes: HashSet::new(),
             }
         }
     }
@@ -149,6 +179,7 @@ impl EmitterWriter {
             cm: code_map,
             short_message,
             teach,
+            error_codes: HashSet::new(),
         }
     }
 
@@ -975,12 +1006,14 @@ impl EmitterWriter {
             if primary_span != &&DUMMY_SP {
                 (cm.lookup_char_pos(primary_span.lo()), cm)
             } else {
-                emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
+                emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
+                                    &mut self.error_codes)?;
                 return Ok(());
             }
         } else {
             // If we don't have span information, emit and exit
-            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
+            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
+                                &mut self.error_codes)?;
             return Ok(());
         };
         if let Ok(pos) =
@@ -1153,7 +1186,8 @@ impl EmitterWriter {
         }
 
         // final step: take our styled buffer, render it, then output it
-        emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
+        emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
+                            &mut self.error_codes)?;
 
         Ok(())
 
@@ -1241,7 +1275,8 @@ impl EmitterWriter {
                 let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
                 buffer.puts(row_num, 0, &msg, Style::NoStyle);
             }
-            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
+            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message,
+                                &mut self.error_codes)?;
         }
         Ok(())
     }
@@ -1269,7 +1304,7 @@ impl EmitterWriter {
                         draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
                     }
                     match emit_to_destination(&buffer.render(), level, &mut self.dst,
-                                              self.short_message) {
+                                              self.short_message, &mut self.error_codes) {
                         Ok(()) => (),
                         Err(e) => panic!("failed to emit error: {}", e)
                     }
@@ -1362,7 +1397,8 @@ fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
 fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
                        lvl: &Level,
                        dst: &mut Destination,
-                       short_message: bool)
+                       short_message: bool,
+                       error_codes: &mut HashSet<String>)
                        -> io::Result<()> {
     use lock;
 
@@ -1383,6 +1419,9 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
         for part in line {
             dst.apply_style(lvl.clone(), part.style)?;
             write!(dst, "{}", part.text)?;
+            if !short_message && part.text.len() == 12 && part.text.starts_with("error[E") {
+                error_codes.insert(part.text[6..11].to_owned());
+            }
             dst.reset_attrs()?;
         }
         if !short_message {