]> git.proxmox.com Git - rustc.git/blob - src/tools/rustfmt/src/format_report_formatter.rs
Update upstream source from tag 'upstream/1.53.0+dfsg1'
[rustc.git] / src / tools / rustfmt / src / format_report_formatter.rs
1 use crate::formatting::FormattingError;
2 use crate::{ErrorKind, FormatReport};
3 use annotate_snippets::display_list::{DisplayList, FormatOptions};
4 use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
5 use std::fmt::{self, Display};
6
7 /// A builder for [`FormatReportFormatter`].
8 pub struct FormatReportFormatterBuilder<'a> {
9 report: &'a FormatReport,
10 enable_colors: bool,
11 }
12
13 impl<'a> FormatReportFormatterBuilder<'a> {
14 /// Creates a new [`FormatReportFormatterBuilder`].
15 pub fn new(report: &'a FormatReport) -> Self {
16 Self {
17 report,
18 enable_colors: false,
19 }
20 }
21
22 /// Enables colors and formatting in the output.
23 pub fn enable_colors(self, enable_colors: bool) -> Self {
24 Self {
25 enable_colors,
26 ..self
27 }
28 }
29
30 /// Creates a new [`FormatReportFormatter`] from the settings in this builder.
31 pub fn build(self) -> FormatReportFormatter<'a> {
32 FormatReportFormatter {
33 report: self.report,
34 enable_colors: self.enable_colors,
35 }
36 }
37 }
38
39 /// Formats the warnings/errors in a [`FormatReport`].
40 ///
41 /// Can be created using a [`FormatReportFormatterBuilder`].
42 pub struct FormatReportFormatter<'a> {
43 report: &'a FormatReport,
44 enable_colors: bool,
45 }
46
47 impl<'a> Display for FormatReportFormatter<'a> {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let errors_by_file = &self.report.internal.borrow().0;
50
51 let opt = FormatOptions {
52 color: self.enable_colors,
53 ..Default::default()
54 };
55
56 for (file, errors) in errors_by_file {
57 for error in errors {
58 let error_kind = error.kind.to_string();
59 let title = Some(Annotation {
60 id: if error.is_internal() {
61 Some("internal")
62 } else {
63 None
64 },
65 label: Some(&error_kind),
66 annotation_type: error_kind_to_snippet_annotation_type(&error.kind),
67 });
68
69 let message_suffix = error.msg_suffix();
70 let footer = if !message_suffix.is_empty() {
71 Some(Annotation {
72 id: None,
73 label: Some(message_suffix),
74 annotation_type: AnnotationType::Note,
75 })
76 } else {
77 None
78 };
79
80 let origin = format!("{}:{}", file, error.line);
81 let slice = Slice {
82 source: &error.line_buffer.clone(),
83 line_start: error.line,
84 origin: Some(origin.as_str()),
85 fold: false,
86 annotations: slice_annotation(error).into_iter().collect(),
87 };
88
89 let snippet = Snippet {
90 title,
91 footer: footer.into_iter().collect(),
92 slices: vec![slice],
93 opt,
94 };
95 writeln!(f, "{}\n", DisplayList::from(snippet))?;
96 }
97 }
98
99 if !errors_by_file.is_empty() {
100 let label = format!(
101 "rustfmt has failed to format. See previous {} errors.",
102 self.report.warning_count()
103 );
104 let snippet = Snippet {
105 title: Some(Annotation {
106 id: None,
107 label: Some(&label),
108 annotation_type: AnnotationType::Warning,
109 }),
110 footer: Vec::new(),
111 slices: Vec::new(),
112 opt,
113 };
114 writeln!(f, "{}", DisplayList::from(snippet))?;
115 }
116
117 Ok(())
118 }
119 }
120
121 fn slice_annotation(error: &FormattingError) -> Option<SourceAnnotation<'_>> {
122 let (range_start, range_length) = error.format_len();
123 let range_end = range_start + range_length;
124
125 if range_length > 0 {
126 Some(SourceAnnotation {
127 annotation_type: AnnotationType::Error,
128 range: (range_start, range_end),
129 label: "",
130 })
131 } else {
132 None
133 }
134 }
135
136 fn error_kind_to_snippet_annotation_type(error_kind: &ErrorKind) -> AnnotationType {
137 match error_kind {
138 ErrorKind::LineOverflow(..)
139 | ErrorKind::TrailingWhitespace
140 | ErrorKind::IoError(_)
141 | ErrorKind::ModuleResolutionError(_)
142 | ErrorKind::ParseError
143 | ErrorKind::LostComment
144 | ErrorKind::LicenseCheck
145 | ErrorKind::BadAttr
146 | ErrorKind::InvalidGlobPattern(_)
147 | ErrorKind::VersionMismatch => AnnotationType::Error,
148 ErrorKind::BadIssue(_) | ErrorKind::DeprecatedAttr => AnnotationType::Warning,
149 }
150 }