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 debug!("buffer: diagnostic={:?}", diagnostic);
186 }
187 buffered_diagnostics.push(*diagnostic);
188 }
189
190 pub fn sub<S: Into<MultiSpan>>(
193 &mut self,
194 level: Level,
195 message: &str,
196 span: Option<S>,
197 ) -> &mut Self {
198 let span = span.map(|s| s.into()).unwrap_or_default();
199 self.diagnostic.sub(level, message, span, None);
200 self
201 }
202
203 pub fn delay_as_bug(&mut self) {
214 self.level = Level::Bug;
215 self.handler.delay_as_bug(*self.diagnostic.clone());
216 self.cancel();
217 }
218
219 pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
226 self.diagnostic.span_label(span, label);
227 self
228 }
229
230 pub fn multipart_suggestion_with_applicability(
231 &mut self,
232 msg: &str,
233 suggestion: Vec<(Span, String)>,
234 applicability: Applicability,
235 ) -> &mut Self {
236 if !self.allow_suggestions {
237 return self;
238 }
239 self.diagnostic
240 .multipart_suggestion_with_applicability(msg, suggestion, applicability);
241 self
242 }
243
244 pub fn span_suggestion_with_applicability(
245 &mut self,
246 sp: Span,
247 msg: &str,
248 suggestion: String,
249 applicability: Applicability,
250 ) -> &mut Self {
251 if !self.allow_suggestions {
252 return self;
253 }
254 self.diagnostic
255 .span_suggestion_with_applicability(sp, msg, suggestion, applicability);
256 self
257 }
258
259 pub fn span_suggestions_with_applicability(
260 &mut self,
261 sp: Span,
262 msg: &str,
263 suggestions: impl Iterator<Item = String>,
264 applicability: Applicability,
265 ) -> &mut Self {
266 if !self.allow_suggestions {
267 return self;
268 }
269 self.diagnostic
270 .span_suggestions_with_applicability(sp, msg, suggestions, applicability);
271 self
272 }
273
274 pub fn span_suggestion_short_with_applicability(
275 &mut self,
276 sp: Span,
277 msg: &str,
278 suggestion: String,
279 applicability: Applicability,
280 ) -> &mut Self {
281 if !self.allow_suggestions {
282 return self;
283 }
284 self.diagnostic.span_suggestion_short_with_applicability(
285 sp,
286 msg,
287 suggestion,
288 applicability,
289 );
290 self
291 }
292
293 pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
294 self.allow_suggestions = allow;
295 self
296 }
297
298 pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
301 DiagnosticBuilder::new_with_code(handler, level, None, message)
302 }
303
304 pub fn new_with_code(
307 handler: &'a Handler,
308 level: Level,
309 code: Option<DiagnosticId>,
310 message: &str,
311 ) -> DiagnosticBuilder<'a> {
312 let diagnostic = Diagnostic::new_with_code(level, code, message);
313 DiagnosticBuilder::new_diagnostic(handler, diagnostic)
314 }
315
316 #[inline(always)] pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
320 DiagnosticBuilder {
321 handler,
322 diagnostic: Box::new(diagnostic),
323 allow_suggestions: true,
324 }
325 }
326}
327
328impl Debug for DiagnosticBuilder<'_> {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 self.diagnostic.fmt(f)
331 }
332}
333
334impl Drop for DiagnosticBuilder<'_> {
337 fn drop(&mut self) {
338 if !panicking() && !self.cancelled() {
339 let mut db = DiagnosticBuilder::new(
340 self.handler,
341 Level::Bug,
342 "Error constructed but not emitted",
343 );
344 db.emit();
345 panic!();
346 }
347 }
348}