]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/emitter.rs
0790f9bc76146d07cf6be1e63356198dbef9611b
[rust.git] / src / librustc_errors / emitter.rs
1 use Destination::*;
2
3 use syntax_pos::{SourceFile, Span, MultiSpan};
4
5 use crate::{
6     Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic,
7     SuggestionStyle, SourceMapperDyn, DiagnosticId,
8 };
9 use crate::Level::Error;
10 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
11 use crate::styled_buffer::StyledBuffer;
12
13 use rustc_data_structures::fx::FxHashMap;
14 use rustc_data_structures::sync::Lrc;
15 use std::borrow::Cow;
16 use std::io::prelude::*;
17 use std::io;
18 use std::cmp::{min, Reverse};
19 use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi};
20 use termcolor::{WriteColor, Color, Buffer};
21
22 const ANONYMIZED_LINE_NUM: &str = "LL";
23
24 /// Emitter trait for emitting errors.
25 pub trait Emitter {
26     /// Emit a structured diagnostic.
27     fn emit(&mut self, db: &DiagnosticBuilder<'_>);
28
29     /// Checks if should show explanations about "rustc --explain"
30     fn should_show_explain(&self) -> bool {
31         true
32     }
33 }
34
35 impl Emitter for EmitterWriter {
36     fn emit(&mut self, db: &DiagnosticBuilder<'_>) {
37         let mut primary_span = db.span.clone();
38         let mut children = db.children.clone();
39         let mut suggestions: &[_] = &[];
40
41         if let Some((sugg, rest)) = db.suggestions.split_first() {
42             if rest.is_empty() &&
43                // don't display multi-suggestions as labels
44                sugg.substitutions.len() == 1 &&
45                // don't display multipart suggestions as labels
46                sugg.substitutions[0].parts.len() == 1 &&
47                // don't display long messages as labels
48                sugg.msg.split_whitespace().count() < 10 &&
49                // don't display multiline suggestions as labels
50                !sugg.substitutions[0].parts[0].snippet.contains('\n') &&
51                // when this style is set we want the suggestion to be a message, not inline
52                sugg.style != SuggestionStyle::HideCodeAlways &&
53                // trivial suggestion for tooling's sake, never shown
54                sugg.style != SuggestionStyle::CompletelyHidden
55             {
56                 let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
57                 let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
58                     // This substitution is only removal or we explicitly don't want to show the
59                     // code inline, don't show it
60                     format!("help: {}", sugg.msg)
61                 } else {
62                     format!("help: {}: `{}`", sugg.msg, substitution)
63                 };
64                 primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
65             } else {
66                 // if there are multiple suggestions, print them all in full
67                 // to be consistent. We could try to figure out if we can
68                 // make one (or the first one) inline, but that would give
69                 // undue importance to a semi-random suggestion
70                 suggestions = &db.suggestions;
71             }
72         }
73
74         self.fix_multispans_in_std_macros(&mut primary_span,
75                                           &mut children,
76                                           &db.level,
77                                           db.handler.flags.external_macro_backtrace);
78
79         self.emit_messages_default(&db.level,
80                                    &db.styled_message(),
81                                    &db.code,
82                                    &primary_span,
83                                    &children,
84                                    &suggestions);
85     }
86
87     fn should_show_explain(&self) -> bool {
88         !self.short_message
89     }
90 }
91
92 /// maximum number of lines we will print for each error; arbitrary.
93 pub const MAX_HIGHLIGHT_LINES: usize = 6;
94 /// maximum number of suggestions to be shown
95 ///
96 /// Arbitrary, but taken from trait import suggestion limit
97 pub const MAX_SUGGESTIONS: usize = 4;
98
99 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
100 pub enum ColorConfig {
101     Auto,
102     Always,
103     Never,
104 }
105
106 impl ColorConfig {
107     fn to_color_choice(&self) -> ColorChoice {
108         match *self {
109             ColorConfig::Always => {
110                 if atty::is(atty::Stream::Stderr) {
111                     ColorChoice::Always
112                 } else {
113                     ColorChoice::AlwaysAnsi
114                 }
115             }
116             ColorConfig::Never => ColorChoice::Never,
117             ColorConfig::Auto if atty::is(atty::Stream::Stderr) => {
118                 ColorChoice::Auto
119             }
120             ColorConfig::Auto => ColorChoice::Never,
121         }
122     }
123 }
124
125 pub struct EmitterWriter {
126     dst: Destination,
127     sm: Option<Lrc<SourceMapperDyn>>,
128     short_message: bool,
129     teach: bool,
130     ui_testing: bool,
131 }
132
133 struct FileWithAnnotatedLines {
134     file: Lrc<SourceFile>,
135     lines: Vec<Line>,
136     multiline_depth: usize,
137 }
138
139 impl EmitterWriter {
140     pub fn stderr(color_config: ColorConfig,
141                   source_map: Option<Lrc<SourceMapperDyn>>,
142                   short_message: bool,
143                   teach: bool)
144                   -> EmitterWriter {
145         let dst = Destination::from_stderr(color_config);
146         EmitterWriter {
147             dst,
148             sm: source_map,
149             short_message,
150             teach,
151             ui_testing: false,
152         }
153     }
154
155     pub fn new(
156         dst: Box<dyn Write + Send>,
157         source_map: Option<Lrc<SourceMapperDyn>>,
158         short_message: bool,
159         teach: bool,
160         colored: bool,
161     ) -> EmitterWriter {
162         EmitterWriter {
163             dst: Raw(dst, colored),
164             sm: source_map,
165             short_message,
166             teach,
167             ui_testing: false,
168         }
169     }
170
171     pub fn ui_testing(mut self, ui_testing: bool) -> Self {
172         self.ui_testing = ui_testing;
173         self
174     }
175
176     fn maybe_anonymized(&self, line_num: usize) -> String {
177         if self.ui_testing {
178             ANONYMIZED_LINE_NUM.to_string()
179         } else {
180             line_num.to_string()
181         }
182     }
183
184     fn preprocess_annotations(&mut self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
185         fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
186                                   file: Lrc<SourceFile>,
187                                   line_index: usize,
188                                   ann: Annotation) {
189
190             for slot in file_vec.iter_mut() {
191                 // Look through each of our files for the one we're adding to
192                 if slot.file.name == file.name {
193                     // See if we already have a line for it
194                     for line_slot in &mut slot.lines {
195                         if line_slot.line_index == line_index {
196                             line_slot.annotations.push(ann);
197                             return;
198                         }
199                     }
200                     // We don't have a line yet, create one
201                     slot.lines.push(Line {
202                         line_index,
203                         annotations: vec![ann],
204                     });
205                     slot.lines.sort();
206                     return;
207                 }
208             }
209             // This is the first time we're seeing the file
210             file_vec.push(FileWithAnnotatedLines {
211                 file,
212                 lines: vec![Line {
213                                 line_index,
214                                 annotations: vec![ann],
215                             }],
216                 multiline_depth: 0,
217             });
218         }
219
220         let mut output = vec![];
221         let mut multiline_annotations = vec![];
222
223         if let Some(ref sm) = self.sm {
224             for span_label in msp.span_labels() {
225                 if span_label.span.is_dummy() {
226                     continue;
227                 }
228
229                 let lo = sm.lookup_char_pos(span_label.span.lo());
230                 let mut hi = sm.lookup_char_pos(span_label.span.hi());
231
232                 // Watch out for "empty spans". If we get a span like 6..6, we
233                 // want to just display a `^` at 6, so convert that to
234                 // 6..7. This is degenerate input, but it's best to degrade
235                 // gracefully -- and the parser likes to supply a span like
236                 // that for EOF, in particular.
237                 if lo.col_display == hi.col_display && lo.line == hi.line {
238                     hi.col_display += 1;
239                 }
240
241                 let ann_type = if lo.line != hi.line {
242                     let ml = MultilineAnnotation {
243                         depth: 1,
244                         line_start: lo.line,
245                         line_end: hi.line,
246                         start_col: lo.col_display,
247                         end_col: hi.col_display,
248                         is_primary: span_label.is_primary,
249                         label: span_label.label.clone(),
250                         overlaps_exactly: false,
251                     };
252                     multiline_annotations.push((lo.file.clone(), ml.clone()));
253                     AnnotationType::Multiline(ml)
254                 } else {
255                     AnnotationType::Singleline
256                 };
257                 let ann = Annotation {
258                     start_col: lo.col_display,
259                     end_col: hi.col_display,
260                     is_primary: span_label.is_primary,
261                     label: span_label.label.clone(),
262                     annotation_type: ann_type,
263                 };
264
265                 if !ann.is_multiline() {
266                     add_annotation_to_file(&mut output, lo.file, lo.line, ann);
267                 }
268             }
269         }
270
271         // Find overlapping multiline annotations, put them at different depths
272         multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end));
273         for item in multiline_annotations.clone() {
274             let ann = item.1;
275             for item in multiline_annotations.iter_mut() {
276                 let ref mut a = item.1;
277                 // Move all other multiline annotations overlapping with this one
278                 // one level to the right.
279                 if !(ann.same_span(a)) &&
280                     num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
281                 {
282                     a.increase_depth();
283                 } else if ann.same_span(a) && &ann != a {
284                     a.overlaps_exactly = true;
285                 } else {
286                     break;
287                 }
288             }
289         }
290
291         let mut max_depth = 0;  // max overlapping multiline spans
292         for (file, ann) in multiline_annotations {
293             if ann.depth > max_depth {
294                 max_depth = ann.depth;
295             }
296             let mut end_ann = ann.as_end();
297             if !ann.overlaps_exactly {
298                 // avoid output like
299                 //
300                 //  |        foo(
301                 //  |   _____^
302                 //  |  |_____|
303                 //  | ||         bar,
304                 //  | ||     );
305                 //  | ||      ^
306                 //  | ||______|
307                 //  |  |______foo
308                 //  |         baz
309                 //
310                 // and instead get
311                 //
312                 //  |       foo(
313                 //  |  _____^
314                 //  | |         bar,
315                 //  | |     );
316                 //  | |      ^
317                 //  | |      |
318                 //  | |______foo
319                 //  |        baz
320                 add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
321                 // 4 is the minimum vertical length of a multiline span when presented: two lines
322                 // of code and two lines of underline. This is not true for the special case where
323                 // the beginning doesn't have an underline, but the current logic seems to be
324                 // working correctly.
325                 let middle = min(ann.line_start + 4, ann.line_end);
326                 for line in ann.line_start + 1..middle {
327                     // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
328                     add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
329                 }
330                 if middle < ann.line_end - 1 {
331                     for line in ann.line_end - 1..ann.line_end {
332                         add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
333                     }
334                 }
335             } else {
336                 end_ann.annotation_type = AnnotationType::Singleline;
337             }
338             add_annotation_to_file(&mut output, file, ann.line_end, end_ann);
339         }
340         for file_vec in output.iter_mut() {
341             file_vec.multiline_depth = max_depth;
342         }
343         output
344     }
345
346     fn render_source_line(&self,
347                           buffer: &mut StyledBuffer,
348                           file: Lrc<SourceFile>,
349                           line: &Line,
350                           width_offset: usize,
351                           code_offset: usize) -> Vec<(usize, Style)> {
352         if line.line_index == 0 {
353             return Vec::new();
354         }
355
356         let source_string = match file.get_line(line.line_index - 1) {
357             Some(s) => s,
358             None => return Vec::new(),
359         };
360
361         let line_offset = buffer.num_lines();
362
363         // First create the source line we will highlight.
364         buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
365         buffer.puts(line_offset,
366                     0,
367                     &self.maybe_anonymized(line.line_index),
368                     Style::LineNumber);
369
370         draw_col_separator(buffer, line_offset, width_offset - 2);
371
372         // Special case when there's only one annotation involved, it is the start of a multiline
373         // span and there's no text at the beginning of the code line. Instead of doing the whole
374         // graph:
375         //
376         // 2 |   fn foo() {
377         //   |  _^
378         // 3 | |
379         // 4 | | }
380         //   | |_^ test
381         //
382         // we simplify the output to:
383         //
384         // 2 | / fn foo() {
385         // 3 | |
386         // 4 | | }
387         //   | |_^ test
388         if line.annotations.len() == 1 {
389             if let Some(ref ann) = line.annotations.get(0) {
390                 if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
391                     if source_string.chars()
392                                     .take(ann.start_col)
393                                     .all(|c| c.is_whitespace()) {
394                         let style = if ann.is_primary {
395                             Style::UnderlinePrimary
396                         } else {
397                             Style::UnderlineSecondary
398                         };
399                         buffer.putc(line_offset,
400                                     width_offset + depth - 1,
401                                     '/',
402                                     style);
403                         return vec![(depth, style)];
404                     }
405                 }
406             }
407         }
408
409         // We want to display like this:
410         //
411         //      vec.push(vec.pop().unwrap());
412         //      ---      ^^^               - previous borrow ends here
413         //      |        |
414         //      |        error occurs here
415         //      previous borrow of `vec` occurs here
416         //
417         // But there are some weird edge cases to be aware of:
418         //
419         //      vec.push(vec.pop().unwrap());
420         //      --------                    - previous borrow ends here
421         //      ||
422         //      |this makes no sense
423         //      previous borrow of `vec` occurs here
424         //
425         // For this reason, we group the lines into "highlight lines"
426         // and "annotations lines", where the highlight lines have the `^`.
427
428         // Sort the annotations by (start, end col)
429         // The labels are reversed, sort and then reversed again.
430         // Consider a list of annotations (A1, A2, C1, C2, B1, B2) where
431         // the letter signifies the span. Here we are only sorting by the
432         // span and hence, the order of the elements with the same span will
433         // not change. On reversing the ordering (|a, b| but b.cmp(a)), you get
434         // (C1, C2, B1, B2, A1, A2). All the elements with the same span are
435         // still ordered first to last, but all the elements with different
436         // spans are ordered by their spans in last to first order. Last to
437         // first order is important, because the jiggly lines and | are on
438         // the left, so the rightmost span needs to be rendered first,
439         // otherwise the lines would end up needing to go over a message.
440
441         let mut annotations = line.annotations.clone();
442         annotations.sort_by_key(|a| Reverse(a.start_col));
443
444         // First, figure out where each label will be positioned.
445         //
446         // In the case where you have the following annotations:
447         //
448         //      vec.push(vec.pop().unwrap());
449         //      --------                    - previous borrow ends here [C]
450         //      ||
451         //      |this makes no sense [B]
452         //      previous borrow of `vec` occurs here [A]
453         //
454         // `annotations_position` will hold [(2, A), (1, B), (0, C)].
455         //
456         // We try, when possible, to stick the rightmost annotation at the end
457         // of the highlight line:
458         //
459         //      vec.push(vec.pop().unwrap());
460         //      ---      ---               - previous borrow ends here
461         //
462         // But sometimes that's not possible because one of the other
463         // annotations overlaps it. For example, from the test
464         // `span_overlap_label`, we have the following annotations
465         // (written on distinct lines for clarity):
466         //
467         //      fn foo(x: u32) {
468         //      --------------
469         //             -
470         //
471         // In this case, we can't stick the rightmost-most label on
472         // the highlight line, or we would get:
473         //
474         //      fn foo(x: u32) {
475         //      -------- x_span
476         //      |
477         //      fn_span
478         //
479         // which is totally weird. Instead we want:
480         //
481         //      fn foo(x: u32) {
482         //      --------------
483         //      |      |
484         //      |      x_span
485         //      fn_span
486         //
487         // which is...less weird, at least. In fact, in general, if
488         // the rightmost span overlaps with any other span, we should
489         // use the "hang below" version, so we can at least make it
490         // clear where the span *starts*. There's an exception for this
491         // logic, when the labels do not have a message:
492         //
493         //      fn foo(x: u32) {
494         //      --------------
495         //             |
496         //             x_span
497         //
498         // instead of:
499         //
500         //      fn foo(x: u32) {
501         //      --------------
502         //      |      |
503         //      |      x_span
504         //      <EMPTY LINE>
505         //
506         let mut annotations_position = vec![];
507         let mut line_len = 0;
508         let mut p = 0;
509         for (i, annotation) in annotations.iter().enumerate() {
510             for (j, next) in annotations.iter().enumerate() {
511                 if overlaps(next, annotation, 0)  // This label overlaps with another one and both
512                     && annotation.has_label()     // take space (they have text and are not
513                     && j > i                      // multiline lines).
514                     && p == 0  // We're currently on the first line, move the label one line down
515                 {
516                     // This annotation needs a new line in the output.
517                     p += 1;
518                     break;
519                 }
520             }
521             annotations_position.push((p, annotation));
522             for (j, next) in annotations.iter().enumerate() {
523                 if j > i  {
524                     let l = if let Some(ref label) = next.label {
525                         label.len() + 2
526                     } else {
527                         0
528                     };
529                     if (overlaps(next, annotation, l) // Do not allow two labels to be in the same
530                                                      // line if they overlap including padding, to
531                                                      // avoid situations like:
532                                                      //
533                                                      //      fn foo(x: u32) {
534                                                      //      -------^------
535                                                      //      |      |
536                                                      //      fn_spanx_span
537                                                      //
538                         && annotation.has_label()    // Both labels must have some text, otherwise
539                         && next.has_label())         // they are not overlapping.
540                                                      // Do not add a new line if this annotation
541                                                      // or the next are vertical line placeholders.
542                         || (annotation.takes_space() // If either this or the next annotation is
543                             && next.has_label())     // multiline start/end, move it to a new line
544                         || (annotation.has_label()   // so as not to overlap the orizontal lines.
545                             && next.takes_space())
546                         || (annotation.takes_space() && next.takes_space())
547                         || (overlaps(next, annotation, l)
548                             && next.end_col <= annotation.end_col
549                             && next.has_label()
550                             && p == 0)  // Avoid #42595.
551                     {
552                         // This annotation needs a new line in the output.
553                         p += 1;
554                         break;
555                     }
556                 }
557             }
558             if line_len < p {
559                 line_len = p;
560             }
561         }
562
563         if line_len != 0 {
564             line_len += 1;
565         }
566
567         // If there are no annotations or the only annotations on this line are
568         // MultilineLine, then there's only code being shown, stop processing.
569         if line.annotations.iter().all(|a| a.is_line()) {
570             return vec![];
571         }
572
573         // Write the colunmn separator.
574         //
575         // After this we will have:
576         //
577         // 2 |   fn foo() {
578         //   |
579         //   |
580         //   |
581         // 3 |
582         // 4 |   }
583         //   |
584         for pos in 0..=line_len {
585             draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2);
586             buffer.putc(line_offset + pos + 1,
587                         width_offset - 2,
588                         '|',
589                         Style::LineNumber);
590         }
591
592         // Write the horizontal lines for multiline annotations
593         // (only the first and last lines need this).
594         //
595         // After this we will have:
596         //
597         // 2 |   fn foo() {
598         //   |  __________
599         //   |
600         //   |
601         // 3 |
602         // 4 |   }
603         //   |  _
604         for &(pos, annotation) in &annotations_position {
605             let style = if annotation.is_primary {
606                 Style::UnderlinePrimary
607             } else {
608                 Style::UnderlineSecondary
609             };
610             let pos = pos + 1;
611             match annotation.annotation_type {
612                 AnnotationType::MultilineStart(depth) |
613                 AnnotationType::MultilineEnd(depth) => {
614                     draw_range(buffer,
615                                '_',
616                                line_offset + pos,
617                                width_offset + depth,
618                                code_offset + annotation.start_col,
619                                style);
620                 }
621                 _ if self.teach => {
622                     buffer.set_style_range(line_offset,
623                                            code_offset + annotation.start_col,
624                                            code_offset + annotation.end_col,
625                                            style,
626                                            annotation.is_primary);
627                 }
628                 _ => {}
629             }
630         }
631
632         // Write the vertical lines for labels that are on a different line as the underline.
633         //
634         // After this we will have:
635         //
636         // 2 |   fn foo() {
637         //   |  __________
638         //   | |    |
639         //   | |
640         // 3 |
641         // 4 | | }
642         //   | |_
643         for &(pos, annotation) in &annotations_position {
644             let style = if annotation.is_primary {
645                 Style::UnderlinePrimary
646             } else {
647                 Style::UnderlineSecondary
648             };
649             let pos = pos + 1;
650
651             if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
652                 for p in line_offset + 1..=line_offset + pos {
653                     buffer.putc(p,
654                                 code_offset + annotation.start_col,
655                                 '|',
656                                 style);
657                 }
658             }
659             match annotation.annotation_type {
660                 AnnotationType::MultilineStart(depth) => {
661                     for p in line_offset + pos + 1..line_offset + line_len + 2 {
662                         buffer.putc(p,
663                                     width_offset + depth - 1,
664                                     '|',
665                                     style);
666                     }
667                 }
668                 AnnotationType::MultilineEnd(depth) => {
669                     for p in line_offset..=line_offset + pos {
670                         buffer.putc(p,
671                                     width_offset + depth - 1,
672                                     '|',
673                                     style);
674                     }
675                 }
676                 _ => (),
677             }
678         }
679
680         // Write the labels on the annotations that actually have a label.
681         //
682         // After this we will have:
683         //
684         // 2 |   fn foo() {
685         //   |  __________
686         //   |      |
687         //   |      something about `foo`
688         // 3 |
689         // 4 |   }
690         //   |  _  test
691         for &(pos, annotation) in &annotations_position {
692             let style = if annotation.is_primary {
693                 Style::LabelPrimary
694             } else {
695                 Style::LabelSecondary
696             };
697             let (pos, col) = if pos == 0 {
698                 (pos + 1, annotation.end_col + 1)
699             } else {
700                 (pos + 2, annotation.start_col)
701             };
702             if let Some(ref label) = annotation.label {
703                 buffer.puts(line_offset + pos,
704                             code_offset + col,
705                             &label,
706                             style);
707             }
708         }
709
710         // Sort from biggest span to smallest span so that smaller spans are
711         // represented in the output:
712         //
713         // x | fn foo()
714         //   | ^^^---^^
715         //   | |  |
716         //   | |  something about `foo`
717         //   | something about `fn foo()`
718         annotations_position.sort_by(|a, b| {
719             // Decreasing order. When `a` and `b` are the same length, prefer `Primary`.
720             (a.1.len(), !a.1.is_primary).cmp(&(b.1.len(), !b.1.is_primary)).reverse()
721         });
722
723         // Write the underlines.
724         //
725         // After this we will have:
726         //
727         // 2 |   fn foo() {
728         //   |  ____-_____^
729         //   |      |
730         //   |      something about `foo`
731         // 3 |
732         // 4 |   }
733         //   |  _^  test
734         for &(_, annotation) in &annotations_position {
735             let (underline, style) = if annotation.is_primary {
736                 ('^', Style::UnderlinePrimary)
737             } else {
738                 ('-', Style::UnderlineSecondary)
739             };
740             for p in annotation.start_col..annotation.end_col {
741                 buffer.putc(line_offset + 1,
742                             code_offset + p,
743                             underline,
744                             style);
745             }
746         }
747         annotations_position.iter().filter_map(|&(_, annotation)| {
748             match annotation.annotation_type {
749                 AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => {
750                     let style = if annotation.is_primary {
751                         Style::LabelPrimary
752                     } else {
753                         Style::LabelSecondary
754                     };
755                     Some((p, style))
756                 }
757                 _ => None
758             }
759
760         }).collect::<Vec<_>>()
761     }
762
763     fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
764         let mut max = 0;
765         if let Some(ref sm) = self.sm {
766             for primary_span in msp.primary_spans() {
767                 if !primary_span.is_dummy() {
768                     let hi = sm.lookup_char_pos(primary_span.hi());
769                     if hi.line > max {
770                         max = hi.line;
771                     }
772                 }
773             }
774             if !self.short_message {
775                 for span_label in msp.span_labels() {
776                     if !span_label.span.is_dummy() {
777                         let hi = sm.lookup_char_pos(span_label.span.hi());
778                         if hi.line > max {
779                             max = hi.line;
780                         }
781                     }
782                 }
783             }
784         }
785         max
786     }
787
788     fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize {
789         let mut max = 0;
790
791         let primary = self.get_multispan_max_line_num(span);
792         max = if primary > max { primary } else { max };
793
794         for sub in children {
795             let sub_result = self.get_multispan_max_line_num(&sub.span);
796             max = if sub_result > max { primary } else { max };
797         }
798         max
799     }
800
801     // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of
802     // <*macros>. Since these locations are often difficult to read, we move these Spans from
803     // <*macros> to their corresponding use site.
804     fn fix_multispan_in_std_macros(&mut self,
805                                    span: &mut MultiSpan,
806                                    always_backtrace: bool) -> bool {
807         let mut spans_updated = false;
808
809         if let Some(ref sm) = self.sm {
810             let mut before_after: Vec<(Span, Span)> = vec![];
811             let mut new_labels: Vec<(Span, String)> = vec![];
812
813             // First, find all the spans in <*macros> and point instead at their use site
814             for sp in span.primary_spans() {
815                 if sp.is_dummy() {
816                     continue;
817                 }
818                 let call_sp = sm.call_span_if_macro(*sp);
819                 if call_sp != *sp && !always_backtrace {
820                     before_after.push((*sp, call_sp));
821                 }
822                 let backtrace_len = sp.macro_backtrace().len();
823                 for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() {
824                     // Only show macro locations that are local
825                     // and display them like a span_note
826                     if let Some(def_site) = trace.def_site_span {
827                         if def_site.is_dummy() {
828                             continue;
829                         }
830                         if always_backtrace {
831                             new_labels.push((def_site,
832                                              format!("in this expansion of `{}`{}",
833                                                      trace.macro_decl_name,
834                                                      if backtrace_len > 2 {
835                                                          // if backtrace_len == 1 it'll be pointed
836                                                          // at by "in this macro invocation"
837                                                          format!(" (#{})", i + 1)
838                                                      } else {
839                                                          String::new()
840                                                      })));
841                         }
842                         // Check to make sure we're not in any <*macros>
843                         if !sm.span_to_filename(def_site).is_macros() &&
844                            !trace.macro_decl_name.starts_with("desugaring of ") &&
845                            !trace.macro_decl_name.starts_with("#[") ||
846                            always_backtrace {
847                             new_labels.push((trace.call_site,
848                                              format!("in this macro invocation{}",
849                                                      if backtrace_len > 2 && always_backtrace {
850                                                          // only specify order when the macro
851                                                          // backtrace is multiple levels deep
852                                                          format!(" (#{})", i + 1)
853                                                      } else {
854                                                          String::new()
855                                                      })));
856                             if !always_backtrace {
857                                 break;
858                             }
859                         }
860                     }
861                 }
862             }
863             for (label_span, label_text) in new_labels {
864                 span.push_span_label(label_span, label_text);
865             }
866             for sp_label in span.span_labels() {
867                 if sp_label.span.is_dummy() {
868                     continue;
869                 }
870                 if sm.span_to_filename(sp_label.span.clone()).is_macros() &&
871                     !always_backtrace
872                 {
873                     let v = sp_label.span.macro_backtrace();
874                     if let Some(use_site) = v.last() {
875                         before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
876                     }
877                 }
878             }
879             // After we have them, make sure we replace these 'bad' def sites with their use sites
880             for (before, after) in before_after {
881                 span.replace(before, after);
882                 spans_updated = true;
883             }
884         }
885
886         spans_updated
887     }
888
889     // This does a small "fix" for multispans by looking to see if it can find any that
890     // point directly at <*macros>. Since these are often difficult to read, this
891     // will change the span to point at the use site.
892     fn fix_multispans_in_std_macros(&mut self,
893                                     span: &mut MultiSpan,
894                                     children: &mut Vec<SubDiagnostic>,
895                                     level: &Level,
896                                     backtrace: bool) {
897         let mut spans_updated = self.fix_multispan_in_std_macros(span, backtrace);
898         for child in children.iter_mut() {
899             spans_updated |= self.fix_multispan_in_std_macros(&mut child.span, backtrace);
900         }
901         let msg = if level == &Error {
902             "this error originates in a macro outside of the current crate \
903              (in Nightly builds, run with -Z external-macro-backtrace \
904               for more info)".to_string()
905         } else {
906             "this warning originates in a macro outside of the current crate \
907              (in Nightly builds, run with -Z external-macro-backtrace \
908               for more info)".to_string()
909         };
910
911         if spans_updated {
912             children.push(SubDiagnostic {
913                 level: Level::Note,
914                 message: vec![
915                     (msg,
916                      Style::NoStyle),
917                 ],
918                 span: MultiSpan::new(),
919                 render_span: None,
920             });
921         }
922     }
923
924     /// Adds a left margin to every line but the first, given a padding length and the label being
925     /// displayed, keeping the provided highlighting.
926     fn msg_to_buffer(&self,
927                      buffer: &mut StyledBuffer,
928                      msg: &[(String, Style)],
929                      padding: usize,
930                      label: &str,
931                      override_style: Option<Style>) {
932
933         // The extra 5 ` ` is padding that's always needed to align to the `note: `:
934         //
935         //   error: message
936         //     --> file.rs:13:20
937         //      |
938         //   13 |     <CODE>
939         //      |      ^^^^
940         //      |
941         //      = note: multiline
942         //              message
943         //   ++^^^----xx
944         //    |  |   | |
945         //    |  |   | magic `2`
946         //    |  |   length of label
947         //    |  magic `3`
948         //    `max_line_num_len`
949         let padding = " ".repeat(padding + label.len() + 5);
950
951         /// Returns `true` if `style`, or the override if present and the style is `NoStyle`.
952         fn style_or_override(style: Style, override_style: Option<Style>) -> Style {
953             if let Some(o) = override_style {
954                 if style == Style::NoStyle {
955                     return o;
956                 }
957             }
958             style
959         }
960
961         let mut line_number = 0;
962
963         // Provided the following diagnostic message:
964         //
965         //     let msg = vec![
966         //       ("
967         //       ("highlighted multiline\nstring to\nsee how it ", Style::NoStyle),
968         //       ("looks", Style::Highlight),
969         //       ("with\nvery ", Style::NoStyle),
970         //       ("weird", Style::Highlight),
971         //       (" formats\n", Style::NoStyle),
972         //       ("see?", Style::Highlight),
973         //     ];
974         //
975         // the expected output on a note is (* surround the highlighted text)
976         //
977         //        = note: highlighted multiline
978         //                string to
979         //                see how it *looks* with
980         //                very *weird* formats
981         //                see?
982         for &(ref text, ref style) in msg.iter() {
983             let lines = text.split('\n').collect::<Vec<_>>();
984             if lines.len() > 1 {
985                 for (i, line) in lines.iter().enumerate() {
986                     if i != 0 {
987                         line_number += 1;
988                         buffer.append(line_number, &padding, Style::NoStyle);
989                     }
990                     buffer.append(line_number, line, style_or_override(*style, override_style));
991                 }
992             } else {
993                 buffer.append(line_number, text, style_or_override(*style, override_style));
994             }
995         }
996     }
997
998     fn emit_message_default(
999         &mut self,
1000         msp: &MultiSpan,
1001         msg: &[(String, Style)],
1002         code: &Option<DiagnosticId>,
1003         level: &Level,
1004         max_line_num_len: usize,
1005         is_secondary: bool,
1006     ) -> io::Result<()> {
1007         let mut buffer = StyledBuffer::new();
1008         let header_style = if is_secondary {
1009             Style::HeaderMsg
1010         } else {
1011             Style::MainHeaderMsg
1012         };
1013
1014         if !msp.has_primary_spans() && !msp.has_span_labels() && is_secondary
1015            && !self.short_message {
1016             // This is a secondary message with no span info
1017             for _ in 0..max_line_num_len {
1018                 buffer.prepend(0, " ", Style::NoStyle);
1019             }
1020             draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
1021             let level_str = level.to_string();
1022             if !level_str.is_empty() {
1023                 buffer.append(0, &level_str, Style::MainHeaderMsg);
1024                 buffer.append(0, ": ", Style::NoStyle);
1025             }
1026             self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
1027         } else {
1028             let level_str = level.to_string();
1029             if !level_str.is_empty() {
1030                 buffer.append(0, &level_str, Style::Level(level.clone()));
1031             }
1032             // only render error codes, not lint codes
1033             if let Some(DiagnosticId::Error(ref code)) = *code {
1034                 buffer.append(0, "[", Style::Level(level.clone()));
1035                 buffer.append(0, &code, Style::Level(level.clone()));
1036                 buffer.append(0, "]", Style::Level(level.clone()));
1037             }
1038             if !level_str.is_empty() {
1039                 buffer.append(0, ": ", header_style);
1040             }
1041             for &(ref text, _) in msg.iter() {
1042                 buffer.append(0, text, header_style);
1043             }
1044         }
1045
1046         // Preprocess all the annotations so that they are grouped by file and by line number
1047         // This helps us quickly iterate over the whole message (including secondary file spans)
1048         let mut annotated_files = self.preprocess_annotations(msp);
1049
1050         // Make sure our primary file comes first
1051         let (primary_lo, sm) = if let (Some(sm), Some(ref primary_span)) =
1052             (self.sm.as_ref(), msp.primary_span().as_ref()) {
1053             if !primary_span.is_dummy() {
1054                 (sm.lookup_char_pos(primary_span.lo()), sm)
1055             } else {
1056                 emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
1057                 return Ok(());
1058             }
1059         } else {
1060             // If we don't have span information, emit and exit
1061             emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
1062             return Ok(());
1063         };
1064         if let Ok(pos) =
1065             annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) {
1066             annotated_files.swap(0, pos);
1067         }
1068
1069         // Print out the annotate source lines that correspond with the error
1070         for annotated_file in annotated_files {
1071             // we can't annotate anything if the source is unavailable.
1072             if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
1073                 continue;
1074             }
1075
1076             // print out the span location and spacer before we print the annotated source
1077             // to do this, we need to know if this span will be primary
1078             let is_primary = primary_lo.file.name == annotated_file.file.name;
1079             if is_primary {
1080                 let loc = primary_lo.clone();
1081                 if !self.short_message {
1082                     // remember where we are in the output buffer for easy reference
1083                     let buffer_msg_line_offset = buffer.num_lines();
1084
1085                     buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
1086                     buffer.append(buffer_msg_line_offset,
1087                                   &format!("{}:{}:{}",
1088                                            loc.file.name,
1089                                            sm.doctest_offset_line(&loc.file.name, loc.line),
1090                                            loc.col.0 + 1),
1091                                   Style::LineAndColumn);
1092                     for _ in 0..max_line_num_len {
1093                         buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
1094                     }
1095                 } else {
1096                     buffer.prepend(0,
1097                                    &format!("{}:{}:{}: ",
1098                                             loc.file.name,
1099                                             sm.doctest_offset_line(&loc.file.name, loc.line),
1100                                             loc.col.0 + 1),
1101                                    Style::LineAndColumn);
1102                 }
1103             } else if !self.short_message {
1104                 // remember where we are in the output buffer for easy reference
1105                 let buffer_msg_line_offset = buffer.num_lines();
1106
1107                 // Add spacing line
1108                 draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
1109
1110                 // Then, the secondary file indicator
1111                 buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
1112                 let loc = if let Some(first_line) = annotated_file.lines.first() {
1113                     let col = if let Some(first_annotation) = first_line.annotations.first() {
1114                         format!(":{}", first_annotation.start_col + 1)
1115                     } else {
1116                         String::new()
1117                     };
1118                     format!("{}:{}{}",
1119                             annotated_file.file.name,
1120                             sm.doctest_offset_line(
1121                                 &annotated_file.file.name, first_line.line_index),
1122                             col)
1123                 } else {
1124                     annotated_file.file.name.to_string()
1125                 };
1126                 buffer.append(buffer_msg_line_offset + 1,
1127                               &loc,
1128                               Style::LineAndColumn);
1129                 for _ in 0..max_line_num_len {
1130                     buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle);
1131                 }
1132             }
1133
1134             if !self.short_message {
1135                 // Put in the spacer between the location and annotated source
1136                 let buffer_msg_line_offset = buffer.num_lines();
1137                 draw_col_separator_no_space(&mut buffer,
1138                                             buffer_msg_line_offset,
1139                                             max_line_num_len + 1);
1140
1141                 // Contains the vertical lines' positions for active multiline annotations
1142                 let mut multilines = FxHashMap::default();
1143
1144                 // Next, output the annotate source for this file
1145                 for line_idx in 0..annotated_file.lines.len() {
1146                     let previous_buffer_line = buffer.num_lines();
1147
1148                     let width_offset = 3 + max_line_num_len;
1149                     let code_offset = if annotated_file.multiline_depth == 0 {
1150                         width_offset
1151                     } else {
1152                         width_offset + annotated_file.multiline_depth + 1
1153                     };
1154
1155                     let depths = self.render_source_line(&mut buffer,
1156                                                          annotated_file.file.clone(),
1157                                                          &annotated_file.lines[line_idx],
1158                                                          width_offset,
1159                                                          code_offset);
1160
1161                     let mut to_add = FxHashMap::default();
1162
1163                     for (depth, style) in depths {
1164                         if multilines.get(&depth).is_some() {
1165                             multilines.remove(&depth);
1166                         } else {
1167                             to_add.insert(depth, style);
1168                         }
1169                     }
1170
1171                     // Set the multiline annotation vertical lines to the left of
1172                     // the code in this line.
1173                     for (depth, style) in &multilines {
1174                         for line in previous_buffer_line..buffer.num_lines() {
1175                             draw_multiline_line(&mut buffer,
1176                                                 line,
1177                                                 width_offset,
1178                                                 *depth,
1179                                                 *style);
1180                         }
1181                     }
1182                     // check to see if we need to print out or elide lines that come between
1183                     // this annotated line and the next one.
1184                     if line_idx < (annotated_file.lines.len() - 1) {
1185                         let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
1186                                              annotated_file.lines[line_idx].line_index;
1187                         if line_idx_delta > 2 {
1188                             let last_buffer_line_num = buffer.num_lines();
1189                             buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
1190
1191                             // Set the multiline annotation vertical lines on `...` bridging line.
1192                             for (depth, style) in &multilines {
1193                                 draw_multiline_line(&mut buffer,
1194                                                     last_buffer_line_num,
1195                                                     width_offset,
1196                                                     *depth,
1197                                                     *style);
1198                             }
1199                         } else if line_idx_delta == 2 {
1200                             let unannotated_line = annotated_file.file
1201                                 .get_line(annotated_file.lines[line_idx].line_index)
1202                                 .unwrap_or_else(|| Cow::from(""));
1203
1204                             let last_buffer_line_num = buffer.num_lines();
1205
1206                             buffer.puts(last_buffer_line_num,
1207                                         0,
1208                                         &self.maybe_anonymized(annotated_file.lines[line_idx + 1]
1209                                                                              .line_index - 1),
1210                                         Style::LineNumber);
1211                             draw_col_separator(&mut buffer,
1212                                                last_buffer_line_num,
1213                                                1 + max_line_num_len);
1214                             buffer.puts(last_buffer_line_num,
1215                                         code_offset,
1216                                         &unannotated_line,
1217                                         Style::Quotation);
1218
1219                             for (depth, style) in &multilines {
1220                                 draw_multiline_line(&mut buffer,
1221                                                     last_buffer_line_num,
1222                                                     width_offset,
1223                                                     *depth,
1224                                                     *style);
1225                             }
1226                         }
1227                     }
1228
1229                     multilines.extend(&to_add);
1230                 }
1231             }
1232         }
1233
1234         // final step: take our styled buffer, render it, then output it
1235         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
1236
1237         Ok(())
1238
1239     }
1240
1241     fn emit_suggestion_default(
1242         &mut self,
1243         suggestion: &CodeSuggestion,
1244         level: &Level,
1245         max_line_num_len: usize,
1246     ) -> io::Result<()> {
1247         if let Some(ref sm) = self.sm {
1248             let mut buffer = StyledBuffer::new();
1249
1250             // Render the suggestion message
1251             let level_str = level.to_string();
1252             if !level_str.is_empty() {
1253                 buffer.append(0, &level_str, Style::Level(level.clone()));
1254                 buffer.append(0, ": ", Style::HeaderMsg);
1255             }
1256             self.msg_to_buffer(
1257                 &mut buffer,
1258                 &[(suggestion.msg.to_owned(), Style::NoStyle)],
1259                 max_line_num_len,
1260                 "suggestion",
1261                 Some(Style::HeaderMsg),
1262             );
1263
1264             // Render the replacements for each suggestion
1265             let suggestions = suggestion.splice_lines(&**sm);
1266
1267             let mut row_num = 2;
1268             for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) {
1269                 // Only show underline if the suggestion spans a single line and doesn't cover the
1270                 // entirety of the code output. If you have multiple replacements in the same line
1271                 // of code, show the underline.
1272                 let show_underline = !(parts.len() == 1
1273                     && parts[0].snippet.trim() == complete.trim())
1274                     && complete.lines().count() == 1;
1275
1276                 let lines = sm.span_to_lines(parts[0].span).unwrap();
1277
1278                 assert!(!lines.lines.is_empty());
1279
1280                 let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
1281                 draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
1282                 let mut line_pos = 0;
1283                 let mut lines = complete.lines();
1284                 for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
1285                     // Print the span column to avoid confusion
1286                     buffer.puts(row_num,
1287                                 0,
1288                                 &self.maybe_anonymized(line_start + line_pos),
1289                                 Style::LineNumber);
1290                     // print the suggestion
1291                     draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
1292                     buffer.append(row_num, line, Style::NoStyle);
1293                     line_pos += 1;
1294                     row_num += 1;
1295                 }
1296
1297                 // This offset and the ones below need to be signed to account for replacement code
1298                 // that is shorter than the original code.
1299                 let mut offset: isize = 0;
1300                 // Only show an underline in the suggestions if the suggestion is not the
1301                 // entirety of the code being shown and the displayed code is not multiline.
1302                 if show_underline {
1303                     draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
1304                     for part in parts {
1305                         let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
1306                         let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
1307
1308                         // Do not underline the leading...
1309                         let start = part.snippet.len()
1310                             .saturating_sub(part.snippet.trim_start().len());
1311                         // ...or trailing spaces. Account for substitutions containing unicode
1312                         // characters.
1313                         let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| {
1314                             acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0)
1315                         });
1316
1317                         let underline_start = (span_start_pos + start) as isize + offset;
1318                         let underline_end = (span_start_pos + start + sub_len) as isize + offset;
1319                         for p in underline_start..underline_end {
1320                             buffer.putc(row_num,
1321                                         max_line_num_len + 3 + p as usize,
1322                                         '^',
1323                                         Style::UnderlinePrimary);
1324                         }
1325                         // underline removals too
1326                         if underline_start == underline_end {
1327                             for p in underline_start-1..underline_start+1 {
1328                                 buffer.putc(row_num,
1329                                             max_line_num_len + 3 + p as usize,
1330                                             '-',
1331                                             Style::UnderlineSecondary);
1332                             }
1333                         }
1334
1335                         // length of the code after substitution
1336                         let full_sub_len = part.snippet.chars().fold(0, |acc, ch| {
1337                             acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) as isize
1338                         });
1339
1340                         // length of the code to be substituted
1341                         let snippet_len = span_end_pos as isize - span_start_pos as isize;
1342                         // For multiple substitutions, use the position *after* the previous
1343                         // substitutions have happened.
1344                         offset += full_sub_len - snippet_len;
1345                     }
1346                     row_num += 1;
1347                 }
1348
1349                 // if we elided some lines, add an ellipsis
1350                 if lines.next().is_some() {
1351                     buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
1352                 } else if !show_underline {
1353                     draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
1354                     row_num += 1;
1355                 }
1356             }
1357             if suggestions.len() > MAX_SUGGESTIONS {
1358                 let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
1359                 buffer.puts(row_num, 0, &msg, Style::NoStyle);
1360             }
1361             emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
1362         }
1363         Ok(())
1364     }
1365
1366     fn emit_messages_default(&mut self,
1367                              level: &Level,
1368                              message: &[(String, Style)],
1369                              code: &Option<DiagnosticId>,
1370                              span: &MultiSpan,
1371                              children: &[SubDiagnostic],
1372                              suggestions: &[CodeSuggestion]) {
1373         let max_line_num_len = if self.ui_testing {
1374             ANONYMIZED_LINE_NUM.len()
1375         } else {
1376             self.get_max_line_num(span, children).to_string().len()
1377         };
1378
1379         match self.emit_message_default(span,
1380                                         message,
1381                                         code,
1382                                         level,
1383                                         max_line_num_len,
1384                                         false) {
1385             Ok(()) => {
1386                 if !children.is_empty() {
1387                     let mut buffer = StyledBuffer::new();
1388                     if !self.short_message {
1389                         draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
1390                     }
1391                     match emit_to_destination(&buffer.render(), level, &mut self.dst,
1392                                               self.short_message) {
1393                         Ok(()) => (),
1394                         Err(e) => panic!("failed to emit error: {}", e)
1395                     }
1396                 }
1397                 if !self.short_message {
1398                     for child in children {
1399                         let span = child.render_span.as_ref().unwrap_or(&child.span);
1400                         match self.emit_message_default(
1401                             &span,
1402                             &child.styled_message(),
1403                             &None,
1404                             &child.level,
1405                             max_line_num_len,
1406                             true,
1407                         ) {
1408                             Err(e) => panic!("failed to emit error: {}", e),
1409                             _ => ()
1410                         }
1411                     }
1412                     for sugg in suggestions {
1413                         if sugg.style == SuggestionStyle::CompletelyHidden {
1414                             // do not display this suggestion, it is meant only for tools
1415                         } else if sugg.style == SuggestionStyle::HideCodeAlways {
1416                             match self.emit_message_default(
1417                                 &MultiSpan::new(),
1418                                 &[(sugg.msg.to_owned(), Style::HeaderMsg)],
1419                                 &None,
1420                                 &Level::Help,
1421                                 max_line_num_len,
1422                                 true,
1423                             ) {
1424                                 Err(e) => panic!("failed to emit error: {}", e),
1425                                 _ => ()
1426                             }
1427                         } else {
1428                             match self.emit_suggestion_default(
1429                                 sugg,
1430                                 &Level::Help,
1431                                 max_line_num_len,
1432                             ) {
1433                                 Err(e) => panic!("failed to emit error: {}", e),
1434                                 _ => ()
1435                             }
1436                         }
1437                     }
1438                 }
1439             }
1440             Err(e) => panic!("failed to emit error: {}", e),
1441         }
1442
1443         let mut dst = self.dst.writable();
1444         match write!(dst, "\n") {
1445             Err(e) => panic!("failed to emit error: {}", e),
1446             _ => {
1447                 match dst.flush() {
1448                     Err(e) => panic!("failed to emit error: {}", e),
1449                     _ => (),
1450                 }
1451             }
1452         }
1453     }
1454 }
1455
1456 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
1457     buffer.puts(line, col, "| ", Style::LineNumber);
1458 }
1459
1460 fn draw_col_separator_no_space(buffer: &mut StyledBuffer, line: usize, col: usize) {
1461     draw_col_separator_no_space_with_style(buffer, line, col, Style::LineNumber);
1462 }
1463
1464 fn draw_col_separator_no_space_with_style(buffer: &mut StyledBuffer,
1465                                           line: usize,
1466                                           col: usize,
1467                                           style: Style) {
1468     buffer.putc(line, col, '|', style);
1469 }
1470
1471 fn draw_range(buffer: &mut StyledBuffer, symbol: char, line: usize,
1472               col_from: usize, col_to: usize, style: Style) {
1473     for col in col_from..col_to {
1474         buffer.putc(line, col, symbol, style);
1475     }
1476 }
1477
1478 fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
1479     buffer.puts(line, col, "= ", Style::LineNumber);
1480 }
1481
1482 fn draw_multiline_line(buffer: &mut StyledBuffer,
1483                        line: usize,
1484                        offset: usize,
1485                        depth: usize,
1486                        style: Style)
1487 {
1488     buffer.putc(line, offset + depth - 1, '|', style);
1489 }
1490
1491 fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool {
1492     let extra = if inclusive {
1493         1
1494     } else {
1495         0
1496     };
1497     (b_start..b_end + extra).contains(&a_start) ||
1498     (a_start..a_end + extra).contains(&b_start)
1499 }
1500 fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
1501     num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false)
1502 }
1503
1504 fn emit_to_destination(rendered_buffer: &[Vec<StyledString>],
1505                        lvl: &Level,
1506                        dst: &mut Destination,
1507                        short_message: bool)
1508                        -> io::Result<()> {
1509     use crate::lock;
1510
1511     let mut dst = dst.writable();
1512
1513     // In order to prevent error message interleaving, where multiple error lines get intermixed
1514     // when multiple compiler processes error simultaneously, we emit errors with additional
1515     // steps.
1516     //
1517     // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When
1518     // the .flush() is called we take the buffer created from the buffered writes and write it at
1519     // one shot.  Because the Unix systems use ANSI for the colors, which is a text-based styling
1520     // scheme, this buffered approach works and maintains the styling.
1521     //
1522     // On Windows, styling happens through calls to a terminal API. This prevents us from using the
1523     // same buffering approach.  Instead, we use a global Windows mutex, which we acquire long
1524     // enough to output the full error message, then we release.
1525     let _buffer_lock = lock::acquire_global_lock("rustc_errors");
1526     for (pos, line) in rendered_buffer.iter().enumerate() {
1527         for part in line {
1528             dst.apply_style(lvl.clone(), part.style)?;
1529             write!(dst, "{}", part.text)?;
1530             dst.reset()?;
1531         }
1532         if !short_message && (!lvl.is_failure_note() || pos != rendered_buffer.len() - 1) {
1533             write!(dst, "\n")?;
1534         }
1535     }
1536     dst.flush()?;
1537     Ok(())
1538 }
1539
1540 pub enum Destination {
1541     Terminal(StandardStream),
1542     Buffered(BufferWriter),
1543     Raw(Box<(dyn Write + Send)>, bool),
1544 }
1545
1546 pub enum WritableDst<'a> {
1547     Terminal(&'a mut StandardStream),
1548     Buffered(&'a mut BufferWriter, Buffer),
1549     Raw(&'a mut (dyn Write + Send)),
1550     ColoredRaw(Ansi<&'a mut (dyn Write + Send)>),
1551 }
1552
1553 impl Destination {
1554     fn from_stderr(color: ColorConfig) -> Destination {
1555         let choice = color.to_color_choice();
1556         // On Windows we'll be performing global synchronization on the entire
1557         // system for emitting rustc errors, so there's no need to buffer
1558         // anything.
1559         //
1560         // On non-Windows we rely on the atomicity of `write` to ensure errors
1561         // don't get all jumbled up.
1562         if cfg!(windows) {
1563             Terminal(StandardStream::stderr(choice))
1564         } else {
1565             Buffered(BufferWriter::stderr(choice))
1566         }
1567     }
1568
1569     fn writable<'a>(&'a mut self) -> WritableDst<'a> {
1570         match *self {
1571             Destination::Terminal(ref mut t) => WritableDst::Terminal(t),
1572             Destination::Buffered(ref mut t) => {
1573                 let buf = t.buffer();
1574                 WritableDst::Buffered(t, buf)
1575             }
1576             Destination::Raw(ref mut t, false) => WritableDst::Raw(t),
1577             Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
1578         }
1579     }
1580 }
1581
1582 impl<'a> WritableDst<'a> {
1583     fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
1584         let mut spec = ColorSpec::new();
1585         match style {
1586             Style::LineAndColumn => {}
1587             Style::LineNumber => {
1588                 spec.set_bold(true);
1589                 spec.set_intense(true);
1590                 if cfg!(windows) {
1591                     spec.set_fg(Some(Color::Cyan));
1592                 } else {
1593                     spec.set_fg(Some(Color::Blue));
1594                 }
1595             }
1596             Style::Quotation => {}
1597             Style::OldSchoolNoteText | Style::MainHeaderMsg => {
1598                 spec.set_bold(true);
1599                 if cfg!(windows) {
1600                     spec.set_intense(true)
1601                         .set_fg(Some(Color::White));
1602                 }
1603             }
1604             Style::UnderlinePrimary | Style::LabelPrimary => {
1605                 spec = lvl.color();
1606                 spec.set_bold(true);
1607             }
1608             Style::UnderlineSecondary |
1609             Style::LabelSecondary => {
1610                 spec.set_bold(true)
1611                     .set_intense(true);
1612                 if cfg!(windows) {
1613                     spec.set_fg(Some(Color::Cyan));
1614                 } else {
1615                     spec.set_fg(Some(Color::Blue));
1616                 }
1617             }
1618             Style::HeaderMsg |
1619             Style::NoStyle => {}
1620             Style::Level(lvl) => {
1621                 spec = lvl.color();
1622                 spec.set_bold(true);
1623             }
1624             Style::Highlight => {
1625                 spec.set_bold(true);
1626             }
1627         }
1628         self.set_color(&spec)
1629     }
1630
1631     fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> {
1632         match *self {
1633             WritableDst::Terminal(ref mut t) => t.set_color(color),
1634             WritableDst::Buffered(_, ref mut t) => t.set_color(color),
1635             WritableDst::ColoredRaw(ref mut t) => t.set_color(color),
1636             WritableDst::Raw(_) => Ok(())
1637         }
1638     }
1639
1640     fn reset(&mut self) -> io::Result<()> {
1641         match *self {
1642             WritableDst::Terminal(ref mut t) => t.reset(),
1643             WritableDst::Buffered(_, ref mut t) => t.reset(),
1644             WritableDst::ColoredRaw(ref mut t) => t.reset(),
1645             WritableDst::Raw(_) => Ok(()),
1646         }
1647     }
1648 }
1649
1650 impl<'a> Write for WritableDst<'a> {
1651     fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
1652         match *self {
1653             WritableDst::Terminal(ref mut t) => t.write(bytes),
1654             WritableDst::Buffered(_, ref mut buf) => buf.write(bytes),
1655             WritableDst::Raw(ref mut w) => w.write(bytes),
1656             WritableDst::ColoredRaw(ref mut t) => t.write(bytes),
1657         }
1658     }
1659
1660     fn flush(&mut self) -> io::Result<()> {
1661         match *self {
1662             WritableDst::Terminal(ref mut t) => t.flush(),
1663             WritableDst::Buffered(_, ref mut buf) => buf.flush(),
1664             WritableDst::Raw(ref mut w) => w.flush(),
1665             WritableDst::ColoredRaw(ref mut w) => w.flush(),
1666         }
1667     }
1668 }
1669
1670 impl<'a> Drop for WritableDst<'a> {
1671     fn drop(&mut self) {
1672         match *self {
1673             WritableDst::Buffered(ref mut dst, ref mut buf) => {
1674                 drop(dst.print(buf));
1675             }
1676             _ => {}
1677         }
1678     }
1679 }