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