1 // FIXME: this can be greatly simplified via $()?
2 // as soon as MRSV hits 1.32
3 
4 /// Build [`Diagnostic`](struct.Diagnostic.html) instance from provided arguments.
5 ///
6 /// # Syntax
7 ///
8 /// See [the guide](index.html#guide).
9 ///
10 #[macro_export]
11 macro_rules! diagnostic {
12     // from alias
13     ($err:expr) => { $crate::Diagnostic::from($err) };
14 
15     // span, message, help
16     ($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{
17         #[allow(unused_imports)]
18         use $crate::__export::{
19             ToTokensAsSpanRange,
20             Span2AsSpanRange,
21             SpanAsSpanRange,
22             SpanRangeAsSpanRange
23         };
24         use $crate::DiagnosticExt;
25         let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
26 
27         let diag = $crate::Diagnostic::spanned_range(
28             span_range,
29             $level,
30             format!($fmt, $($args),*)
31         );
32         $crate::__pme__suggestions!(diag $($rest)*);
33         diag
34     }};
35 
36     ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{
37         #[allow(unused_imports)]
38         use $crate::__export::{
39             ToTokensAsSpanRange,
40             Span2AsSpanRange,
41             SpanAsSpanRange,
42             SpanRangeAsSpanRange
43         };
44         use $crate::DiagnosticExt;
45         let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
46 
47         let diag = $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string());
48         $crate::__pme__suggestions!(diag $($rest)*);
49         diag
50     }};
51 
52     // span, message, no help
53     ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{
54         #[allow(unused_imports)]
55         use $crate::__export::{
56             ToTokensAsSpanRange,
57             Span2AsSpanRange,
58             SpanAsSpanRange,
59             SpanRangeAsSpanRange
60         };
61         use $crate::DiagnosticExt;
62         let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
63 
64         $crate::Diagnostic::spanned_range(
65             span_range,
66             $level,
67             format!($fmt, $($args),*)
68         )
69     }};
70 
71     ($span:expr, $level:expr, $msg:expr) => {{
72         #[allow(unused_imports)]
73         use $crate::__export::{
74             ToTokensAsSpanRange,
75             Span2AsSpanRange,
76             SpanAsSpanRange,
77             SpanRangeAsSpanRange
78         };
79         use $crate::DiagnosticExt;
80         let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
81 
82         $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string())
83     }};
84 
85 
86     // trailing commas
87 
88     ($span:expr, $level:expr, $fmt:expr, $($args:expr),+, ; $($rest:tt)+) => {
89         $crate::diagnostic!($span, $level, $fmt, $($args),* ; $($rest)*)
90     };
91     ($span:expr, $level:expr, $msg:expr, ; $($rest:tt)+) => {
92         $crate::diagnostic!($span, $level, $msg ; $($rest)*)
93     };
94     ($span:expr, $level:expr, $fmt:expr, $($args:expr),+,) => {
95         $crate::diagnostic!($span, $level, $fmt, $($args),*)
96     };
97     ($span:expr, $level:expr, $msg:expr,) => {
98         $crate::diagnostic!($span, $level, $msg)
99     };
100     // ($err:expr,) => { $crate::diagnostic!($err) };
101 }
102 
103 /// Abort proc-macro execution right now and display the error.
104 ///
105 /// # Syntax
106 ///
107 /// See [the guide](index.html#guide).
108 #[macro_export]
109 macro_rules! abort {
110     ($err:expr) => {
111         $crate::diagnostic!($err).abort()
112     };
113 
114     ($span:expr, $($tts:tt)*) => {
115         $crate::diagnostic!($span, $crate::Level::Error, $($tts)*).abort()
116     };
117 }
118 
119 /// Shortcut for `abort!(Span::call_site(), msg...)`. This macro
120 /// is still preferable over plain panic, panics are not for error reporting.
121 ///
122 /// # Syntax
123 ///
124 /// See [the guide](index.html#guide).
125 ///
126 #[macro_export]
127 macro_rules! abort_call_site {
128     ($($tts:tt)*) => {
129         $crate::abort!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
130     };
131 }
132 
133 /// Emit an error while not aborting the proc-macro right away.
134 ///
135 /// # Syntax
136 ///
137 /// See [the guide](index.html#guide).
138 ///
139 #[macro_export]
140 macro_rules! emit_error {
141     ($err:expr) => {
142         $crate::diagnostic!($err).emit()
143     };
144 
145     ($span:expr, $($tts:tt)*) => {{
146         let level = $crate::Level::Error;
147         $crate::diagnostic!($span, level, $($tts)*).emit()
148     }};
149 }
150 
151 /// Shortcut for `emit_error!(Span::call_site(), ...)`. This macro
152 /// is still preferable over plain panic, panics are not for error reporting..
153 ///
154 /// # Syntax
155 ///
156 /// See [the guide](index.html#guide).
157 ///
158 #[macro_export]
159 macro_rules! emit_call_site_error {
160     ($($tts:tt)*) => {
161         $crate::emit_error!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
162     };
163 }
164 
165 /// Emit a warning. Warnings are not errors and compilation won't fail because of them.
166 ///
167 /// **Does nothing on stable**
168 ///
169 /// # Syntax
170 ///
171 /// See [the guide](index.html#guide).
172 ///
173 #[macro_export]
174 macro_rules! emit_warning {
175     ($span:expr, $($tts:tt)*) => {
176         $crate::diagnostic!($span, $crate::Level::Warning, $($tts)*).emit()
177     };
178 }
179 
180 /// Shortcut for `emit_warning!(Span::call_site(), ...)`.
181 ///
182 /// **Does nothing on stable**
183 ///
184 /// # Syntax
185 ///
186 /// See [the guide](index.html#guide).
187 ///
188 #[macro_export]
189 macro_rules! emit_call_site_warning {
190     ($($tts:tt)*) => {{
191         $crate::emit_warning!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
192     }};
193 }
194 
195 #[doc(hidden)]
196 #[macro_export]
197 macro_rules! __pme__suggestions {
198     ($var:ident) => ();
199 
200     ($var:ident $help:ident =? $msg:expr) => {
201         let $var = if let Some(msg) = $msg {
202             $var.suggestion(stringify!($help), msg.to_string())
203         } else {
204             $var
205         };
206     };
207     ($var:ident $help:ident =? $span:expr => $msg:expr) => {
208         let $var = if let Some(msg) = $msg {
209             $var.span_suggestion($span.into(), stringify!($help), msg.to_string())
210         } else {
211             $var
212         };
213     };
214 
215     ($var:ident $help:ident =? $msg:expr ; $($rest:tt)*) => {
216         $crate::__pme__suggestions!($var $help =? $msg);
217         $crate::__pme__suggestions!($var $($rest)*);
218     };
219     ($var:ident $help:ident =? $span:expr => $msg:expr ; $($rest:tt)*) => {
220         $crate::__pme__suggestions!($var $help =? $span => $msg);
221         $crate::__pme__suggestions!($var $($rest)*);
222     };
223 
224 
225     ($var:ident $help:ident = $msg:expr) => {
226         let $var = $var.suggestion(stringify!($help), $msg.to_string());
227     };
228     ($var:ident $help:ident = $fmt:expr, $($args:expr),+) => {
229         let $var = $var.suggestion(
230             stringify!($help),
231             format!($fmt, $($args),*)
232         );
233     };
234     ($var:ident $help:ident = $span:expr => $msg:expr) => {
235         let $var = $var.span_suggestion($span.into(), stringify!($help), $msg.to_string());
236     };
237     ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+) => {
238         let $var = $var.span_suggestion(
239             $span.into(),
240             stringify!($help),
241             format!($fmt, $($args),*)
242         );
243     };
244 
245     ($var:ident $help:ident = $msg:expr ; $($rest:tt)*) => {
246         $crate::__pme__suggestions!($var $help = $msg);
247         $crate::__pme__suggestions!($var $($rest)*);
248     };
249     ($var:ident $help:ident = $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => {
250         $crate::__pme__suggestions!($var $help = $fmt, $($args),*);
251         $crate::__pme__suggestions!($var $($rest)*);
252     };
253     ($var:ident $help:ident = $span:expr => $msg:expr ; $($rest:tt)*) => {
254         $crate::__pme__suggestions!($var $help = $span => $msg);
255         $crate::__pme__suggestions!($var $($rest)*);
256     };
257     ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => {
258         $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*);
259         $crate::__pme__suggestions!($var $($rest)*);
260     };
261 
262     // trailing commas
263 
264     ($var:ident $help:ident = $msg:expr,) => {
265         $crate::__pme__suggestions!($var $help = $msg)
266     };
267     ($var:ident $help:ident = $fmt:expr, $($args:expr),+,) => {
268         $crate::__pme__suggestions!($var $help = $fmt, $($args)*)
269     };
270     ($var:ident $help:ident = $span:expr => $msg:expr,) => {
271         $crate::__pme__suggestions!($var $help = $span => $msg)
272     };
273     ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),*,) => {
274         $crate::__pme__suggestions!($var $help = $span => $fmt, $($args)*)
275     };
276     ($var:ident $help:ident = $msg:expr, ; $($rest:tt)*) => {
277         $crate::__pme__suggestions!($var $help = $msg; $($rest)*)
278     };
279     ($var:ident $help:ident = $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => {
280         $crate::__pme__suggestions!($var $help = $fmt, $($args),*; $($rest)*)
281     };
282     ($var:ident $help:ident = $span:expr => $msg:expr, ; $($rest:tt)*) => {
283         $crate::__pme__suggestions!($var $help = $span => $msg; $($rest)*)
284     };
285     ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => {
286         $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*; $($rest)*)
287     };
288 }
289