]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/diagnostic_builder.rs
Auto merge of #56737 - nnethercote:TokenStream-improvements, r=petrochenkov
[rust.git] / src / librustc_errors / diagnostic_builder.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use Diagnostic;
12 use DiagnosticId;
13 use DiagnosticStyledString;
14 use Applicability;
15
16 use Level;
17 use Handler;
18 use std::fmt::{self, Debug};
19 use std::ops::{Deref, DerefMut};
20 use std::thread::panicking;
21 use syntax_pos::{MultiSpan, Span};
22
23 /// Used for emitting structured error messages and other diagnostic information.
24 ///
25 /// If there is some state in a downstream crate you would like to
26 /// access in the methods of `DiagnosticBuilder` here, consider
27 /// extending `HandlerFlags`, accessed via `self.handler.flags`.
28 #[must_use]
29 #[derive(Clone)]
30 pub struct DiagnosticBuilder<'a> {
31     pub handler: &'a Handler,
32     diagnostic: Diagnostic,
33     allow_suggestions: bool,
34 }
35
36 /// In general, the `DiagnosticBuilder` uses deref to allow access to
37 /// the fields and methods of the embedded `diagnostic` in a
38 /// transparent way.  *However,* many of the methods are intended to
39 /// be used in a chained way, and hence ought to return `self`. In
40 /// that case, we can't just naively forward to the method on the
41 /// `diagnostic`, because the return type would be a `&Diagnostic`
42 /// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
43 /// it easy to declare such methods on the builder.
44 macro_rules! forward {
45     // Forward pattern for &self -> &Self
46     (pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => {
47         pub fn $n(&self, $($name: $ty),*) -> &Self {
48             #[allow(deprecated)]
49             self.diagnostic.$n($($name),*);
50             self
51         }
52     };
53
54     // Forward pattern for &mut self -> &mut Self
55     (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => {
56         pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
57             #[allow(deprecated)]
58             self.diagnostic.$n($($name),*);
59             self
60         }
61     };
62
63     // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
64     // type parameter. No obvious way to make this more generic.
65     (pub fn $n:ident<S: Into<MultiSpan>>(
66                     &mut self,
67                     $($name:ident: $ty:ty),*
68                     $(,)*) -> &mut Self) => {
69         pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
70             #[allow(deprecated)]
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     #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
191     forward!(pub fn span_suggestion_short(
192                                       &mut self,
193                                       sp: Span,
194                                       msg: &str,
195                                       suggestion: String,
196                                       ) -> &mut Self);
197
198     #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
199     forward!(pub fn multipart_suggestion(
200         &mut self,
201         msg: &str,
202         suggestion: Vec<(Span, String)>,
203     ) -> &mut Self);
204
205     #[deprecated(note = "Use `span_suggestion_with_applicability`")]
206     forward!(pub fn span_suggestion(&mut self,
207                                     sp: Span,
208                                     msg: &str,
209                                     suggestion: String,
210                                     ) -> &mut Self);
211
212     #[deprecated(note = "Use `span_suggestions_with_applicability`")]
213     forward!(pub fn span_suggestions(&mut self,
214                                      sp: Span,
215                                      msg: &str,
216                                      suggestions: Vec<String>,
217                                      ) -> &mut Self);
218
219     pub fn multipart_suggestion_with_applicability(&mut self,
220                                               msg: &str,
221                                               suggestion: Vec<(Span, String)>,
222                                               applicability: Applicability,
223                                               ) -> &mut Self {
224         if !self.allow_suggestions {
225             return self
226         }
227         self.diagnostic.multipart_suggestion_with_applicability(
228             msg,
229             suggestion,
230             applicability,
231         );
232         self
233     }
234
235     pub fn span_suggestion_with_applicability(&mut self,
236                                               sp: Span,
237                                               msg: &str,
238                                               suggestion: String,
239                                               applicability: Applicability)
240                                               -> &mut Self {
241         if !self.allow_suggestions {
242             return self
243         }
244         self.diagnostic.span_suggestion_with_applicability(
245             sp,
246             msg,
247             suggestion,
248             applicability,
249         );
250         self
251     }
252
253     pub fn span_suggestions_with_applicability(&mut self,
254                                                sp: Span,
255                                                msg: &str,
256                                                suggestions: impl Iterator<Item = String>,
257                                                applicability: Applicability)
258                                                -> &mut Self {
259         if !self.allow_suggestions {
260             return self
261         }
262         self.diagnostic.span_suggestions_with_applicability(
263             sp,
264             msg,
265             suggestions,
266             applicability,
267         );
268         self
269     }
270
271     pub fn span_suggestion_short_with_applicability(&mut self,
272                                                     sp: Span,
273                                                     msg: &str,
274                                                     suggestion: String,
275                                                     applicability: Applicability)
276                                                     -> &mut Self {
277         if !self.allow_suggestions {
278             return self
279         }
280         self.diagnostic.span_suggestion_short_with_applicability(
281             sp,
282             msg,
283             suggestion,
284             applicability,
285         );
286         self
287     }
288     forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
289     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
290
291     pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
292         self.allow_suggestions = allow;
293         self
294     }
295
296     /// Convenience function for internal use, clients should use one of the
297     /// struct_* methods on Handler.
298     pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
299         DiagnosticBuilder::new_with_code(handler, level, None, message)
300     }
301
302     /// Convenience function for internal use, clients should use one of the
303     /// struct_* methods on Handler.
304     pub fn new_with_code(handler: &'a Handler,
305                          level: Level,
306                          code: Option<DiagnosticId>,
307                          message: &str)
308                          -> DiagnosticBuilder<'a> {
309         let diagnostic = Diagnostic::new_with_code(level, code, message);
310         DiagnosticBuilder::new_diagnostic(handler, diagnostic)
311     }
312
313     /// Creates a new `DiagnosticBuilder` with an already constructed
314     /// diagnostic.
315     pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
316                          -> DiagnosticBuilder<'a> {
317         DiagnosticBuilder {
318             handler,
319             diagnostic,
320             allow_suggestions: true,
321         }
322     }
323 }
324
325 impl<'a> Debug for DiagnosticBuilder<'a> {
326     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
327         self.diagnostic.fmt(f)
328     }
329 }
330
331 /// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled
332 /// or we emit a bug.
333 impl<'a> Drop for DiagnosticBuilder<'a> {
334     fn drop(&mut self) {
335         if !panicking() && !self.cancelled() {
336             let mut db = DiagnosticBuilder::new(self.handler,
337                                                 Level::Bug,
338                                                 "Error constructed but not emitted");
339             db.emit();
340             panic!();
341         }
342     }
343 }