1use std::{
12 fmt::{self, Debug},
13 ops::{Deref, DerefMut},
14 thread::panicking,
15};
16
17use tracing::debug;
18
19use super::{Applicability, Diagnostic, DiagnosticId, DiagnosticStyledString, Handler, Level};
20use crate::syntax_pos::{MultiSpan, Span};
21
22#[must_use]
29#[derive(Clone)]
30pub struct DiagnosticBuilder<'a> {
31 pub handler: &'a Handler,
32 #[cfg(not(feature = "__plugin_mode"))]
33 pub(crate) diagnostic: Box<Diagnostic>,
34 #[cfg(feature = "__plugin_mode")]
35 pub diagnostic: Box<Diagnostic>,
36 allow_suggestions: bool,
37}
38
39#[allow(unused)]
48macro_rules! forward {
49 (pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => {
51 pub fn $n(&self, $($name: $ty),*) -> &Self {
52 #[allow(deprecated)]
53 self.diagnostic.$n($($name),*);
54 self
55 }
56 };
57
58 (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => {
60 pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
61 #[allow(deprecated)]
62 self.diagnostic.$n($($name),*);
63 self
64 }
65 };
66
67 (pub fn $n:ident<S: Into<MultiSpan>>(
70 &mut self,
71 $($name:ident: $ty:ty),*
72 $(,)*) -> &mut Self) => {
73 pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
74 #[allow(deprecated)]
75 self.diagnostic.$n($($name),*);
76 self
77 }
78 };
79}
80
81impl Deref for DiagnosticBuilder<'_> {
82 type Target = Diagnostic;
83
84 fn deref(&self) -> &Diagnostic {
85 &self.diagnostic
86 }
87}
88
89impl DerefMut for DiagnosticBuilder<'_> {
90 fn deref_mut(&mut self) -> &mut Diagnostic {
91 &mut self.diagnostic
92 }
93}
94
95impl<'a> DiagnosticBuilder<'a> {
96 forward!(pub fn note_expected_found(&mut self,
97 label: &dyn fmt::Display,
98 expected: DiagnosticStyledString,
99 found: DiagnosticStyledString,
100 ) -> &mut Self);
101
102 forward!(pub fn note_expected_found_extra(&mut self,
103 label: &dyn fmt::Display,
104 expected: DiagnosticStyledString,
105 found: DiagnosticStyledString,
106 expected_extra: &dyn fmt::Display,
107 found_extra: &dyn fmt::Display,
108 ) -> &mut Self);
109
110 forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
111
112 forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
113 sp: S,
114 msg: &str,
115 ) -> &mut Self);
116
117 forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
118
119 forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
120
121 forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
122
123 forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
124 sp: S,
125 msg: &str,
126 ) -> &mut Self);
127
128 forward!(pub fn span_suggestion_short(
129 &mut self,
130 sp: Span,
131 msg: &str,
132 suggestion: String,
133 ) -> &mut Self);
134
135 forward!(pub fn multipart_suggestion(
136 &mut self,
137 msg: &str,
138 suggestion: Vec<(Span, String)>,
139 ) -> &mut Self);
140
141 forward!(pub fn span_suggestion(&mut self,
142 sp: Span,
143 msg: &str,
144 suggestion: String,
145 ) -> &mut Self);
146
147 forward!(pub fn span_suggestions(&mut self,
148 sp: Span,
149 msg: &str,
150 suggestions: Vec<String>,
151 ) -> &mut Self);
152
153 forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
154
155 forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
156
157 pub fn emit(&mut self) {
159 if self.cancelled() {
160 return;
161 }
162
163 self.handler.emit_db(self);
164 self.cancel();
165 }
166
167 pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
170 if self.handler.flags.dont_buffer_diagnostics || self.handler.flags.treat_err_as_bug {
171 self.emit();
172 return;
173 }
174
175 let diagnostic;
178 unsafe {
179 diagnostic = ::std::ptr::read(&self.diagnostic);
180 ::std::mem::forget(self);
181 };
182 if cfg!(feature = "debug") {
185 #[cfg(debug_assertions)]
186 debug!("buffer: diagnostic={:?}", diagnostic);
187 }
188 buffered_diagnostics.push(*diagnostic);
189 }
190
191 pub fn sub<S: Into<MultiSpan>>(
194 &mut self,
195 level: Level,
196 message: &str,
197 span: Option<S>,
198 ) -> &mut Self {
199 let span = span.map(|s| s.into()).unwrap_or_default();
200 self.diagnostic.sub(level, message, span, None);
201 self
202 }
203
204 pub fn delay_as_bug(&mut self) {
215 self.level = Level::Bug;
216 self.handler.delay_as_bug(*self.diagnostic.clone());
217 self.cancel();
218 }
219
220 pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
227 self.diagnostic.span_label(span, label);
228 self
229 }
230
231 pub fn multipart_suggestion_with_applicability(
232 &mut self,
233 msg: &str,
234 suggestion: Vec<(Span, String)>,
235 applicability: Applicability,
236 ) -> &mut Self {
237 if !self.allow_suggestions {
238 return self;
239 }
240 self.diagnostic
241 .multipart_suggestion_with_applicability(msg, suggestion, applicability);
242 self
243 }
244
245 pub fn span_suggestion_with_applicability(
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
256 .span_suggestion_with_applicability(sp, msg, suggestion, applicability);
257 self
258 }
259
260 pub fn span_suggestions_with_applicability(
261 &mut self,
262 sp: Span,
263 msg: &str,
264 suggestions: impl Iterator<Item = String>,
265 applicability: Applicability,
266 ) -> &mut Self {
267 if !self.allow_suggestions {
268 return self;
269 }
270 self.diagnostic
271 .span_suggestions_with_applicability(sp, msg, suggestions, applicability);
272 self
273 }
274
275 pub fn span_suggestion_short_with_applicability(
276 &mut self,
277 sp: Span,
278 msg: &str,
279 suggestion: String,
280 applicability: Applicability,
281 ) -> &mut Self {
282 if !self.allow_suggestions {
283 return self;
284 }
285 self.diagnostic.span_suggestion_short_with_applicability(
286 sp,
287 msg,
288 suggestion,
289 applicability,
290 );
291 self
292 }
293
294 pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
295 self.allow_suggestions = allow;
296 self
297 }
298
299 pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
302 DiagnosticBuilder::new_with_code(handler, level, None, message)
303 }
304
305 pub fn new_with_code(
308 handler: &'a Handler,
309 level: Level,
310 code: Option<DiagnosticId>,
311 message: &str,
312 ) -> DiagnosticBuilder<'a> {
313 let diagnostic = Diagnostic::new_with_code(level, code, message);
314 DiagnosticBuilder::new_diagnostic(handler, diagnostic)
315 }
316
317 #[inline(always)] pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
321 DiagnosticBuilder {
322 handler,
323 diagnostic: Box::new(diagnostic),
324 allow_suggestions: true,
325 }
326 }
327
328 pub fn take(&mut self) -> Diagnostic {
329 std::mem::take(&mut *self.diagnostic)
330 }
331}
332
333impl Debug for DiagnosticBuilder<'_> {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 self.diagnostic.fmt(f)
336 }
337}
338
339impl Drop for DiagnosticBuilder<'_> {
342 fn drop(&mut self) {
343 if !panicking() && !self.cancelled() {
344 let mut db = DiagnosticBuilder::new(
345 self.handler,
346 Level::Bug,
347 "Error constructed but not emitted",
348 );
349 db.emit();
350 panic!();
351 }
352 }
353}