3 use DiagnosticStyledString;
8 use std::fmt::{self, Debug};
9 use std::ops::{Deref, DerefMut};
10 use std::thread::panicking;
11 use syntax_pos::{MultiSpan, Span};
13 /// Used for emitting structured error messages and other diagnostic information.
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`.
20 pub struct DiagnosticBuilder<'a> {
21 pub handler: &'a Handler,
22 diagnostic: Diagnostic,
23 allow_suggestions: bool,
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
38 pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self
41 pub fn $n(&self, $($name: $ty),*) -> &Self {
42 self.diagnostic.$n($($name),*);
47 // Forward pattern for &mut self -> &mut Self
50 pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self
53 pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
54 self.diagnostic.$n($($name),*);
59 // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
60 // type parameter. No obvious way to make this more generic.
63 pub fn $n:ident<S: Into<MultiSpan>>(
65 $($name:ident: $ty:ty),*
70 pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
71 self.diagnostic.$n($($name),*);
77 impl<'a> Deref for DiagnosticBuilder<'a> {
78 type Target = Diagnostic;
80 fn deref(&self) -> &Diagnostic {
85 impl<'a> DerefMut for DiagnosticBuilder<'a> {
86 fn deref_mut(&mut self) -> &mut Diagnostic {
91 impl<'a> DiagnosticBuilder<'a> {
92 /// Emit the diagnostic.
93 pub fn emit(&mut self) {
98 self.handler.emit_db(&self);
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 {
110 // We need to use `ptr::read` because `DiagnosticBuilder`
111 // implements `Drop`.
114 diagnostic = ::std::ptr::read(&self.diagnostic);
115 ::std::mem::forget(self);
117 // Logging here is useful to help track down where in logs an error was
119 debug!("buffer: diagnostic={:?}", diagnostic);
120 buffered_diagnostics.push(diagnostic);
123 /// Convenience function for internal use, clients should use one of the
124 /// span_* methods instead.
125 pub fn sub<S: Into<MultiSpan>>(
131 let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
132 self.diagnostic.sub(level, message, span, None);
136 /// Delay emission of this diagnostic as a bug.
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
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());
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);
163 forward!(pub fn note_expected_found(&mut self,
164 label: &dyn fmt::Display,
165 expected: DiagnosticStyledString,
166 found: DiagnosticStyledString,
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,
177 forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
178 forward!(pub fn span_note<S: Into<MultiSpan>>(&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,
190 pub fn multipart_suggestion(
193 suggestion: Vec<(Span, String)>,
194 applicability: Applicability,
196 if !self.allow_suggestions {
199 self.diagnostic.multipart_suggestion(
207 pub fn span_suggestion(
212 applicability: Applicability,
214 if !self.allow_suggestions {
217 self.diagnostic.span_suggestion(
226 pub fn span_suggestions(
230 suggestions: impl Iterator<Item = String>,
231 applicability: Applicability,
233 if !self.allow_suggestions {
236 self.diagnostic.span_suggestions(
245 pub fn span_suggestion_short(
250 applicability: Applicability,
252 if !self.allow_suggestions {
255 self.diagnostic.span_suggestion_short(
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);
266 pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
267 self.allow_suggestions = allow;
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)
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,
281 code: Option<DiagnosticId>,
283 -> DiagnosticBuilder<'a> {
284 let diagnostic = Diagnostic::new_with_code(level, code, message);
285 DiagnosticBuilder::new_diagnostic(handler, diagnostic)
288 /// Creates a new `DiagnosticBuilder` with an already constructed
290 pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
291 -> DiagnosticBuilder<'a> {
295 allow_suggestions: true,
300 impl<'a> Debug for DiagnosticBuilder<'a> {
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
302 self.diagnostic.fmt(f)
306 /// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled
307 /// or we emit a bug.
308 impl<'a> Drop for DiagnosticBuilder<'a> {
310 if !panicking() && !self.cancelled() {
311 let mut db = DiagnosticBuilder::new(self.handler,
313 "Error constructed but not emitted");