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