]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_errors/emitter.rs
Rollup merge of #61686 - phansch:librustc_errors_docs, r=estebank
[rust.git] / src / librustc_errors / emitter.rs
index b56162deaf1cc68b093f489527f52a39f7892c67..fca8298409a61f5add93a7a787e6c4f6ba04cda2 100644 (file)
@@ -1,3 +1,12 @@
+//! The current rustc diagnostics emitter.
+//!
+//! An `Emitter` takes care of generating the output from a `DiagnosticBuilder` struct.
+//!
+//! There are various `Emitter` implementations that generate different output formats such as
+//! JSON and human readable output.
+//!
+//! The output types are defined in `librustc::session::config::ErrorOutputType`.
+
 use Destination::*;
 
 use syntax_pos::{SourceFile, Span, MultiSpan};
@@ -24,6 +33,7 @@
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum HumanReadableErrorType {
     Default(ColorConfig),
+    AnnotateSnippet(ColorConfig),
     Short(ColorConfig),
 }
 
@@ -33,6 +43,7 @@ pub fn unzip(self) -> (bool, ColorConfig) {
         match self {
             HumanReadableErrorType::Default(cc) => (false, cc),
             HumanReadableErrorType::Short(cc) => (true, cc),
+            HumanReadableErrorType::AnnotateSnippet(cc) => (false, cc),
         }
     }
     pub fn new_emitter(
@@ -162,6 +173,7 @@ fn suggests_using_colors(self) -> bool {
     }
 }
 
+/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
 pub struct EmitterWriter {
     dst: Destination,
     sm: Option<Lrc<SourceMapperDyn>>,
@@ -170,9 +182,10 @@ pub struct EmitterWriter {
     ui_testing: bool,
 }
 
-struct FileWithAnnotatedLines {
-    file: Lrc<SourceFile>,
-    lines: Vec<Line>,
+#[derive(Debug)]
+pub struct FileWithAnnotatedLines {
+    pub file: Lrc<SourceFile>,
+    pub lines: Vec<Line>,
     multiline_depth: usize,
 }
 
@@ -221,169 +234,6 @@ fn maybe_anonymized(&self, line_num: usize) -> String {
         }
     }
 
-    fn preprocess_annotations(&mut self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
-        fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
-                                  file: Lrc<SourceFile>,
-                                  line_index: usize,
-                                  ann: Annotation) {
-
-            for slot in file_vec.iter_mut() {
-                // Look through each of our files for the one we're adding to
-                if slot.file.name == file.name {
-                    // See if we already have a line for it
-                    for line_slot in &mut slot.lines {
-                        if line_slot.line_index == line_index {
-                            line_slot.annotations.push(ann);
-                            return;
-                        }
-                    }
-                    // We don't have a line yet, create one
-                    slot.lines.push(Line {
-                        line_index,
-                        annotations: vec![ann],
-                    });
-                    slot.lines.sort();
-                    return;
-                }
-            }
-            // This is the first time we're seeing the file
-            file_vec.push(FileWithAnnotatedLines {
-                file,
-                lines: vec![Line {
-                                line_index,
-                                annotations: vec![ann],
-                            }],
-                multiline_depth: 0,
-            });
-        }
-
-        let mut output = vec![];
-        let mut multiline_annotations = vec![];
-
-        if let Some(ref sm) = self.sm {
-            for span_label in msp.span_labels() {
-                if span_label.span.is_dummy() {
-                    continue;
-                }
-
-                let lo = sm.lookup_char_pos(span_label.span.lo());
-                let mut hi = sm.lookup_char_pos(span_label.span.hi());
-
-                // Watch out for "empty spans". If we get a span like 6..6, we
-                // want to just display a `^` at 6, so convert that to
-                // 6..7. This is degenerate input, but it's best to degrade
-                // gracefully -- and the parser likes to supply a span like
-                // that for EOF, in particular.
-
-                if lo.col_display == hi.col_display && lo.line == hi.line {
-                    hi.col_display += 1;
-                }
-
-                let ann_type = if lo.line != hi.line {
-                    let ml = MultilineAnnotation {
-                        depth: 1,
-                        line_start: lo.line,
-                        line_end: hi.line,
-                        start_col: lo.col_display,
-                        end_col: hi.col_display,
-                        is_primary: span_label.is_primary,
-                        label: span_label.label.clone(),
-                        overlaps_exactly: false,
-                    };
-                    multiline_annotations.push((lo.file.clone(), ml.clone()));
-                    AnnotationType::Multiline(ml)
-                } else {
-                    AnnotationType::Singleline
-                };
-                let ann = Annotation {
-                    start_col: lo.col_display,
-                    end_col: hi.col_display,
-                    is_primary: span_label.is_primary,
-                    label: span_label.label.clone(),
-                    annotation_type: ann_type,
-                };
-
-                if !ann.is_multiline() {
-                    add_annotation_to_file(&mut output, lo.file, lo.line, ann);
-                }
-            }
-        }
-
-        // Find overlapping multiline annotations, put them at different depths
-        multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end));
-        for item in multiline_annotations.clone() {
-            let ann = item.1;
-            for item in multiline_annotations.iter_mut() {
-                let ref mut a = item.1;
-                // Move all other multiline annotations overlapping with this one
-                // one level to the right.
-                if !(ann.same_span(a)) &&
-                    num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
-                {
-                    a.increase_depth();
-                } else if ann.same_span(a) && &ann != a {
-                    a.overlaps_exactly = true;
-                } else {
-                    break;
-                }
-            }
-        }
-
-        let mut max_depth = 0;  // max overlapping multiline spans
-        for (file, ann) in multiline_annotations {
-            if ann.depth > max_depth {
-                max_depth = ann.depth;
-            }
-            let mut end_ann = ann.as_end();
-            if !ann.overlaps_exactly {
-                // avoid output like
-                //
-                //  |        foo(
-                //  |   _____^
-                //  |  |_____|
-                //  | ||         bar,
-                //  | ||     );
-                //  | ||      ^
-                //  | ||______|
-                //  |  |______foo
-                //  |         baz
-                //
-                // and instead get
-                //
-                //  |       foo(
-                //  |  _____^
-                //  | |         bar,
-                //  | |     );
-                //  | |      ^
-                //  | |      |
-                //  | |______foo
-                //  |        baz
-                add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
-                // 4 is the minimum vertical length of a multiline span when presented: two lines
-                // of code and two lines of underline. This is not true for the special case where
-                // the beginning doesn't have an underline, but the current logic seems to be
-                // working correctly.
-                let middle = min(ann.line_start + 4, ann.line_end);
-                for line in ann.line_start + 1..middle {
-                    // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
-                    add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
-                }
-                if middle < ann.line_end - 1 {
-                    for line in ann.line_end - 1..ann.line_end {
-                        add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
-                    }
-                }
-            } else {
-                end_ann.annotation_type = AnnotationType::Singleline;
-            }
-            add_annotation_to_file(&mut output, file, ann.line_end, end_ann);
-        }
-        for file_vec in output.iter_mut() {
-            file_vec.multiline_depth = max_depth;
-        }
-        output
-    }
-
     fn render_source_line(&self,
                           buffer: &mut StyledBuffer,
                           file: Lrc<SourceFile>,
@@ -1093,9 +943,7 @@ fn emit_message_default(
             }
         }
 
-        // Preprocess all the annotations so that they are grouped by file and by line number
-        // This helps us quickly iterate over the whole message (including secondary file spans)
-        let mut annotated_files = self.preprocess_annotations(msp);
+        let mut annotated_files = FileWithAnnotatedLines::collect_annotations(msp, &self.sm);
 
         // Make sure our primary file comes first
         let (primary_lo, sm) = if let (Some(sm), Some(ref primary_span)) =
@@ -1503,6 +1351,176 @@ fn emit_messages_default(&mut self,
     }
 }
 
+impl FileWithAnnotatedLines {
+    /// Preprocess all the annotations so that they are grouped by file and by line number
+    /// This helps us quickly iterate over the whole message (including secondary file spans)
+    pub fn collect_annotations(
+        msp: &MultiSpan,
+        source_map: &Option<Lrc<SourceMapperDyn>>
+    ) -> Vec<FileWithAnnotatedLines> {
+        fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
+                                  file: Lrc<SourceFile>,
+                                  line_index: usize,
+                                  ann: Annotation) {
+
+            for slot in file_vec.iter_mut() {
+                // Look through each of our files for the one we're adding to
+                if slot.file.name == file.name {
+                    // See if we already have a line for it
+                    for line_slot in &mut slot.lines {
+                        if line_slot.line_index == line_index {
+                            line_slot.annotations.push(ann);
+                            return;
+                        }
+                    }
+                    // We don't have a line yet, create one
+                    slot.lines.push(Line {
+                        line_index,
+                        annotations: vec![ann],
+                    });
+                    slot.lines.sort();
+                    return;
+                }
+            }
+            // This is the first time we're seeing the file
+            file_vec.push(FileWithAnnotatedLines {
+                file,
+                lines: vec![Line {
+                                line_index,
+                                annotations: vec![ann],
+                            }],
+                multiline_depth: 0,
+            });
+        }
+
+        let mut output = vec![];
+        let mut multiline_annotations = vec![];
+
+        if let Some(ref sm) = source_map {
+            for span_label in msp.span_labels() {
+                if span_label.span.is_dummy() {
+                    continue;
+                }
+
+                let lo = sm.lookup_char_pos(span_label.span.lo());
+                let mut hi = sm.lookup_char_pos(span_label.span.hi());
+
+                // Watch out for "empty spans". If we get a span like 6..6, we
+                // want to just display a `^` at 6, so convert that to
+                // 6..7. This is degenerate input, but it's best to degrade
+                // gracefully -- and the parser likes to supply a span like
+                // that for EOF, in particular.
+
+                if lo.col_display == hi.col_display && lo.line == hi.line {
+                    hi.col_display += 1;
+                }
+
+                let ann_type = if lo.line != hi.line {
+                    let ml = MultilineAnnotation {
+                        depth: 1,
+                        line_start: lo.line,
+                        line_end: hi.line,
+                        start_col: lo.col_display,
+                        end_col: hi.col_display,
+                        is_primary: span_label.is_primary,
+                        label: span_label.label.clone(),
+                        overlaps_exactly: false,
+                    };
+                    multiline_annotations.push((lo.file.clone(), ml.clone()));
+                    AnnotationType::Multiline(ml)
+                } else {
+                    AnnotationType::Singleline
+                };
+                let ann = Annotation {
+                    start_col: lo.col_display,
+                    end_col: hi.col_display,
+                    is_primary: span_label.is_primary,
+                    label: span_label.label.clone(),
+                    annotation_type: ann_type,
+                };
+
+                if !ann.is_multiline() {
+                    add_annotation_to_file(&mut output, lo.file, lo.line, ann);
+                }
+            }
+        }
+
+        // Find overlapping multiline annotations, put them at different depths
+        multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end));
+        for item in multiline_annotations.clone() {
+            let ann = item.1;
+            for item in multiline_annotations.iter_mut() {
+                let ref mut a = item.1;
+                // Move all other multiline annotations overlapping with this one
+                // one level to the right.
+                if !(ann.same_span(a)) &&
+                    num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
+                {
+                    a.increase_depth();
+                } else if ann.same_span(a) && &ann != a {
+                    a.overlaps_exactly = true;
+                } else {
+                    break;
+                }
+            }
+        }
+
+        let mut max_depth = 0;  // max overlapping multiline spans
+        for (file, ann) in multiline_annotations {
+            if ann.depth > max_depth {
+                max_depth = ann.depth;
+            }
+            let mut end_ann = ann.as_end();
+            if !ann.overlaps_exactly {
+                // avoid output like
+                //
+                //  |        foo(
+                //  |   _____^
+                //  |  |_____|
+                //  | ||         bar,
+                //  | ||     );
+                //  | ||      ^
+                //  | ||______|
+                //  |  |______foo
+                //  |         baz
+                //
+                // and instead get
+                //
+                //  |       foo(
+                //  |  _____^
+                //  | |         bar,
+                //  | |     );
+                //  | |      ^
+                //  | |      |
+                //  | |______foo
+                //  |        baz
+                add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
+                // 4 is the minimum vertical length of a multiline span when presented: two lines
+                // of code and two lines of underline. This is not true for the special case where
+                // the beginning doesn't have an underline, but the current logic seems to be
+                // working correctly.
+                let middle = min(ann.line_start + 4, ann.line_end);
+                for line in ann.line_start + 1..middle {
+                    // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
+                    add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
+                }
+                if middle < ann.line_end - 1 {
+                    for line in ann.line_end - 1..ann.line_end {
+                        add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
+                    }
+                }
+            } else {
+                end_ann.annotation_type = AnnotationType::Singleline;
+            }
+            add_annotation_to_file(&mut output, file, ann.line_end, end_ann);
+        }
+        for file_vec in output.iter_mut() {
+            file_vec.multiline_depth = max_depth;
+        }
+        output
+    }
+}
+
 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
     buffer.puts(line, col, "| ", Style::LineNumber);
 }
@@ -1645,7 +1663,7 @@ fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
                 }
             }
             Style::Quotation => {}
-            Style::OldSchoolNoteText | Style::MainHeaderMsg => {
+            Style::MainHeaderMsg => {
                 spec.set_bold(true);
                 if cfg!(windows) {
                     spec.set_intense(true)