]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/diagnostic_builder.rs
Auto merge of #57927 - Alexendoo:mem-drop-nll-docs, r=Centril
[rust.git] / src / librustc_errors / diagnostic_builder.rs
1 use Diagnostic;
2 use DiagnosticId;
3 use DiagnosticStyledString;
4 use Applicability;
5
6 use Level;
7 use Handler;
8 use std::fmt::{self, Debug};
9 use std::ops::{Deref, DerefMut};
10 use std::thread::panicking;
11 use syntax_pos::{MultiSpan, Span};
12
13 /// Used for emitting structured error messages and other diagnostic information.
14 ///
15 /// If there is some state in a downstream crate you would like to
16 /// access in the methods of `DiagnosticBuilder` here, consider
17 /// extending `HandlerFlags`, accessed via `self.handler.flags`.
18 #[must_use]
19 #[derive(Clone)]
20 pub struct DiagnosticBuilder<'a> {
21     pub handler: &'a Handler,
22     diagnostic: Diagnostic,
23     allow_suggestions: bool,
24 }
25
26 /// In general, the `DiagnosticBuilder` uses deref to allow access to
27 /// the fields and methods of the embedded `diagnostic` in a
28 /// transparent way.  *However,* many of the methods are intended to
29 /// be used in a chained way, and hence ought to return `self`. In
30 /// that case, we can't just naively forward to the method on the
31 /// `diagnostic`, because the return type would be a `&Diagnostic`
32 /// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
33 /// it easy to declare such methods on the builder.
34 macro_rules! forward {
35     // Forward pattern for &self -> &Self
36     (
37         $(#[$attrs:meta])*
38         pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self
39     ) => {
40         $(#[$attrs])*
41         pub fn $n(&self, $($name: $ty),*) -> &Self {
42             self.diagnostic.$n($($name),*);
43             self
44         }
45     };
46
47     // Forward pattern for &mut self -> &mut Self
48     (
49         $(#[$attrs:meta])*
50         pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self
51     ) => {
52         $(#[$attrs])*
53         pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
54             self.diagnostic.$n($($name),*);
55             self
56         }
57     };
58
59     // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
60     // type parameter. No obvious way to make this more generic.
61     (
62         $(#[$attrs:meta])*
63         pub fn $n:ident<S: Into<MultiSpan>>(
64             &mut self,
65             $($name:ident: $ty:ty),*
66             $(,)*
67         ) -> &mut Self
68     ) => {
69         $(#[$attrs])*
70         pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
71             self.diagnostic.$n($($name),*);
72             self
73         }
74     };
75 }
76
77 impl<'a> Deref for DiagnosticBuilder<'a> {
78     type Target = Diagnostic;
79
80     fn deref(&self) -> &Diagnostic {
81         &self.diagnostic
82     }
83 }
84
85 impl<'a> DerefMut for DiagnosticBuilder<'a> {
86     fn deref_mut(&mut self) -> &mut Diagnostic {
87         &mut self.diagnostic
88     }
89 }
90
91 impl<'a> DiagnosticBuilder<'a> {
92     /// Emit the diagnostic.
93     pub fn emit(&mut self) {
94         if self.cancelled() {
95             return;
96         }
97
98         self.handler.emit_db(&self);
99         self.cancel();
100     }
101
102     /// Buffers the diagnostic for later emission, unless handler
103     /// has disabled such buffering.
104     pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
105         if self.handler.flags.dont_buffer_diagnostics || self.handler.flags.treat_err_as_bug {
106             self.emit();
107             return;
108         }
109
110         // We need to use `ptr::read` because `DiagnosticBuilder`
111         // implements `Drop`.
112         let diagnostic;
113         unsafe {
114             diagnostic = ::std::ptr::read(&self.diagnostic);
115             ::std::mem::forget(self);
116         };
117         // Logging here is useful to help track down where in logs an error was
118         // actually emitted.
119         debug!("buffer: diagnostic={:?}", diagnostic);
120         buffered_diagnostics.push(diagnostic);
121     }
122
123     /// Convenience function for internal use, clients should use one of the
124     /// span_* methods instead.
125     pub fn sub<S: Into<MultiSpan>>(
126         &mut self,
127         level: Level,
128         message: &str,
129         span: Option<S>,
130     ) -> &mut Self {
131         let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
132         self.diagnostic.sub(level, message, span, None);
133         self
134     }
135
136     /// Delay emission of this diagnostic as a bug.
137     ///
138     /// This can be useful in contexts where an error indicates a bug but
139     /// typically this only happens when other compilation errors have already
140     /// happened. In those cases this can be used to defer emission of this
141     /// diagnostic as a bug in the compiler only if no other errors have been
142     /// emitted.
143     ///
144     /// In the meantime, though, callsites are required to deal with the "bug"
145     /// locally in whichever way makes the most sense.
146     pub fn delay_as_bug(&mut self) {
147         self.level = Level::Bug;
148         self.handler.delay_as_bug(self.diagnostic.clone());
149         self.cancel();
150     }
151
152     /// Add a span/label to be included in the resulting snippet.
153     /// This is pushed onto the `MultiSpan` that was created when the
154     /// diagnostic was first built. If you don't call this function at
155     /// all, and you just supplied a `Span` to create the diagnostic,
156     /// then the snippet will just include that `Span`, which is
157     /// called the primary span.
158     pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
159         self.diagnostic.span_label(span, label);
160         self
161     }
162
163     forward!(pub fn note_expected_found(&mut self,
164                                         label: &dyn fmt::Display,
165                                         expected: DiagnosticStyledString,
166                                         found: DiagnosticStyledString,
167                                         ) -> &mut Self);
168
169     forward!(pub fn note_expected_found_extra(&mut self,
170                                               label: &dyn fmt::Display,
171                                               expected: DiagnosticStyledString,
172                                               found: DiagnosticStyledString,
173                                               expected_extra: &dyn fmt::Display,
174                                               found_extra: &dyn fmt::Display,
175                                               ) -> &mut Self);
176
177     forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
178     forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
179                                                   sp: S,
180                                                   msg: &str,
181                                                   ) -> &mut Self);
182     forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
183     forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
184     forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
185     forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
186                                                   sp: S,
187                                                   msg: &str,
188                                                   ) -> &mut Self);
189
190     pub fn multipart_suggestion(
191         &mut self,
192         msg: &str,
193         suggestion: Vec<(Span, String)>,
194         applicability: Applicability,
195     ) -> &mut Self {
196         if !self.allow_suggestions {
197             return self
198         }
199         self.diagnostic.multipart_suggestion(
200             msg,
201             suggestion,
202             applicability,
203         );
204         self
205     }
206
207     pub fn span_suggestion(
208         &mut self,
209         sp: Span,
210         msg: &str,
211         suggestion: String,
212         applicability: Applicability,
213     ) -> &mut Self {
214         if !self.allow_suggestions {
215             return self
216         }
217         self.diagnostic.span_suggestion(
218             sp,
219             msg,
220             suggestion,
221             applicability,
222         );
223         self
224     }
225
226     pub fn span_suggestions(
227         &mut self,
228         sp: Span,
229         msg: &str,
230         suggestions: impl Iterator<Item = String>,
231         applicability: Applicability,
232     ) -> &mut Self {
233         if !self.allow_suggestions {
234             return self
235         }
236         self.diagnostic.span_suggestions(
237             sp,
238             msg,
239             suggestions,
240             applicability,
241         );
242         self
243     }
244
245     pub fn span_suggestion_short(
246         &mut self,
247         sp: Span,
248         msg: &str,
249         suggestion: String,
250         applicability: Applicability,
251     ) -> &mut Self {
252         if !self.allow_suggestions {
253             return self
254         }
255         self.diagnostic.span_suggestion_short(
256             sp,
257             msg,
258             suggestion,
259             applicability,
260         );
261         self
262     }
263     forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
264     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
265
266     pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
267         self.allow_suggestions = allow;
268         self
269     }
270
271     /// Convenience function for internal use, clients should use one of the
272     /// struct_* methods on Handler.
273     pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
274         DiagnosticBuilder::new_with_code(handler, level, None, message)
275     }
276
277     /// Convenience function for internal use, clients should use one of the
278     /// struct_* methods on Handler.
279     pub fn new_with_code(handler: &'a Handler,
280                          level: Level,
281                          code: Option<DiagnosticId>,
282                          message: &str)
283                          -> DiagnosticBuilder<'a> {
284         let diagnostic = Diagnostic::new_with_code(level, code, message);
285         DiagnosticBuilder::new_diagnostic(handler, diagnostic)
286     }
287
288     /// Creates a new `DiagnosticBuilder` with an already constructed
289     /// diagnostic.
290     pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
291                          -> DiagnosticBuilder<'a> {
292         DiagnosticBuilder {
293             handler,
294             diagnostic,
295             allow_suggestions: true,
296         }
297     }
298 }
299
300 impl<'a> Debug for DiagnosticBuilder<'a> {
301     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
302         self.diagnostic.fmt(f)
303     }
304 }
305
306 /// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled
307 /// or we emit a bug.
308 impl<'a> Drop for DiagnosticBuilder<'a> {
309     fn drop(&mut self) {
310         if !panicking() && !self.cancelled() {
311             let mut db = DiagnosticBuilder::new(self.handler,
312                                                 Level::Bug,
313                                                 "Error constructed but not emitted");
314             db.emit();
315             panic!();
316         }
317     }
318 }