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