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