1 #[macro_use]
2 extern crate proc_macro_error;
3 extern crate proc_macro;
4
5 use proc_macro2::{Span, TokenStream};
6 use proc_macro_error::{
7 abort, abort_call_site, diagnostic, emit_call_site_warning, emit_error, emit_warning,
8 proc_macro_error, set_dummy, Diagnostic, Level, OptionExt, ResultExt, SpanRange,
9 };
10
11 use syn::{parse_macro_input, spanned::Spanned};
12
13 // Macros and Diagnostic
14
15 #[proc_macro]
16 #[proc_macro_error]
abort_from(input: proc_macro::TokenStream) -> proc_macro::TokenStream17 pub fn abort_from(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
18 let span = input.into_iter().next().unwrap().span();
19 abort!(
20 span,
21 syn::Error::new(Span::call_site(), "abort!(span, from) test")
22 )
23 }
24
25 #[proc_macro]
26 #[proc_macro_error]
abort_to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream27 pub fn abort_to_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
28 let span = input.into_iter().next().unwrap().span();
29 abort!(span, "abort!(span, single_expr) test")
30 }
31
32 #[proc_macro]
33 #[proc_macro_error]
abort_format(input: proc_macro::TokenStream) -> proc_macro::TokenStream34 pub fn abort_format(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
35 let span = input.into_iter().next().unwrap().span();
36 abort!(span, "abort!(span, expr1, {}) test", "expr2")
37 }
38
39 #[proc_macro]
40 #[proc_macro_error]
abort_call_site_test(_: proc_macro::TokenStream) -> proc_macro::TokenStream41 pub fn abort_call_site_test(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
42 abort_call_site!("abort_call_site! test")
43 }
44
45 #[proc_macro]
46 #[proc_macro_error]
direct_abort(input: proc_macro::TokenStream) -> proc_macro::TokenStream47 pub fn direct_abort(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
48 let span = input.into_iter().next().unwrap().span();
49 Diagnostic::spanned(span.into(), Level::Error, "Diagnostic::abort() test".into()).abort()
50 }
51
52 #[proc_macro]
53 #[proc_macro_error]
emit(input: proc_macro::TokenStream) -> proc_macro::TokenStream54 pub fn emit(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
55 let mut spans = input.into_iter().step_by(2).map(|t| t.span());
56 emit_error!(
57 spans.next().unwrap(),
58 syn::Error::new(Span::call_site(), "emit!(span, from) test")
59 );
60 emit_error!(
61 spans.next().unwrap(),
62 "emit!(span, expr1, {}) test",
63 "expr2"
64 );
65 emit_error!(spans.next().unwrap(), "emit!(span, single_expr) test");
66 Diagnostic::spanned(
67 spans.next().unwrap().into(),
68 Level::Error,
69 "Diagnostic::emit() test".into(),
70 )
71 .emit();
72
73 emit_call_site_error!("emit_call_site_error!(expr) test");
74
75 // NOOP on stable, just checking that the macros themselves compile.
76 emit_warning!(spans.next().unwrap(), "emit_warning! test");
77 emit_call_site_warning!("emit_call_site_warning! test");
78
79 quote!().into()
80 }
81
82 // Notes
83
84 #[proc_macro]
85 #[proc_macro_error]
abort_notes(input: proc_macro::TokenStream) -> proc_macro::TokenStream86 pub fn abort_notes(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
87 let mut spans = input.into_iter().map(|s| s.span());
88 let span = spans.next().unwrap();
89 let span2 = spans.next().unwrap();
90
91 let some_note = Some("Some note");
92 let none_note: Option<&'static str> = None;
93
94 abort! {
95 span, "This is {} error", "an";
96
97 note = "simple note";
98 help = "simple help";
99 hint = "simple hint";
100 yay = "simple yay";
101
102 note = "format {}", "note";
103
104 note =? some_note;
105 note =? none_note;
106
107 note = span2 => "spanned simple note";
108 note = span2 => "spanned format {}", "note";
109 note =? span2 => some_note;
110 note =? span2 => none_note;
111 }
112 }
113
114 #[proc_macro]
115 #[proc_macro_error]
emit_notes(input: proc_macro::TokenStream) -> proc_macro::TokenStream116 pub fn emit_notes(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
117 let mut spans = input.into_iter().step_by(2).map(|s| s.span());
118 let span = spans.next().unwrap();
119 let span2 = spans.next().unwrap();
120
121 let some_note = Some("Some note");
122 let none_note: Option<&'static str> = None;
123
124 abort! {
125 span, "This is {} error", "an";
126
127 note = "simple note";
128 help = "simple help";
129 hint = "simple hint";
130 yay = "simple yay";
131
132 note = "format {}", "note";
133
134 note =? some_note;
135 note =? none_note;
136
137 note = span2 => "spanned simple note";
138 note = span2 => "spanned format {}", "note";
139 note =? span2 => some_note;
140 note =? span2 => none_note;
141 }
142 }
143
144 // Extension traits
145
146 #[proc_macro]
147 #[proc_macro_error]
option_ext(_input: proc_macro::TokenStream) -> proc_macro::TokenStream148 pub fn option_ext(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
149 let none: Option<Diagnostic> = None;
150 none.expect_or_abort("Option::expect_or_abort() test");
151 quote!().into()
152 }
153
154 #[proc_macro]
155 #[proc_macro_error]
result_unwrap_or_abort(input: proc_macro::TokenStream) -> proc_macro::TokenStream156 pub fn result_unwrap_or_abort(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
157 let span = input.into_iter().next().unwrap().span();
158 let err = Diagnostic::spanned(
159 span.into(),
160 Level::Error,
161 "Result::unwrap_or_abort() test".to_string(),
162 );
163 let res: Result<(), _> = Err(err);
164 res.unwrap_or_abort();
165 quote!().into()
166 }
167
168 #[proc_macro]
169 #[proc_macro_error]
result_expect_or_abort(input: proc_macro::TokenStream) -> proc_macro::TokenStream170 pub fn result_expect_or_abort(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
171 let span = input.into_iter().next().unwrap().span();
172 let err = Diagnostic::spanned(
173 span.into(),
174 Level::Error,
175 "Result::expect_or_abort() test".to_string(),
176 );
177 let res: Result<(), _> = Err(err);
178 res.expect_or_abort("BOOM");
179 quote!().into()
180 }
181
182 // Dummy
183
184 #[proc_macro]
185 #[proc_macro_error]
dummy(input: proc_macro::TokenStream) -> proc_macro::TokenStream186 pub fn dummy(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
187 let span = input.into_iter().next().unwrap().span();
188 set_dummy(quote! {
189 impl Default for NeedDefault {
190 fn default() -> Self { NeedDefault::A }
191 }
192 });
193
194 abort!(span, "set_dummy test")
195 }
196
197 #[proc_macro]
198 #[proc_macro_error]
append_dummy(input: proc_macro::TokenStream) -> proc_macro::TokenStream199 pub fn append_dummy(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
200 let span = input.into_iter().next().unwrap().span();
201 set_dummy(quote! {
202 impl Default for NeedDefault
203 });
204
205 proc_macro_error::append_dummy(quote!({
206 fn default() -> Self {
207 NeedDefault::A
208 }
209 }));
210
211 abort!(span, "append_dummy test")
212 }
213
214 // Panic
215
216 #[proc_macro]
217 #[proc_macro_error]
unrelated_panic(_input: proc_macro::TokenStream) -> proc_macro::TokenStream218 pub fn unrelated_panic(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
219 panic!("unrelated panic test")
220 }
221
222 // Success
223
224 #[proc_macro]
225 #[proc_macro_error]
ok(input: proc_macro::TokenStream) -> proc_macro::TokenStream226 pub fn ok(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
227 let input = TokenStream::from(input);
228 quote!(fn #input() {}).into()
229 }
230
231 // Multiple tokens
232
233 #[proc_macro_attribute]
234 #[proc_macro_error]
multiple_tokens( _: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream235 pub fn multiple_tokens(
236 _: proc_macro::TokenStream,
237 input: proc_macro::TokenStream,
238 ) -> proc_macro::TokenStream {
239 let input = proc_macro2::TokenStream::from(input);
240 abort!(input, "...");
241 }
242
243 #[proc_macro]
244 #[proc_macro_error]
to_tokens_span(input: proc_macro::TokenStream) -> proc_macro::TokenStream245 pub fn to_tokens_span(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
246 let ty = parse_macro_input!(input as syn::Type);
247 emit_error!(ty, "whole type");
248 emit_error!(ty.span(), "explicit .span()");
249 quote!().into()
250 }
251
252 #[proc_macro]
253 #[proc_macro_error]
explicit_span_range(input: proc_macro::TokenStream) -> proc_macro::TokenStream254 pub fn explicit_span_range(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
255 let mut spans = input.into_iter().step_by(2).map(|s| s.span());
256 let first = Span::from(spans.next().unwrap());
257 let last = Span::from(spans.nth(1).unwrap());
258 abort!(SpanRange { first, last }, "explicit SpanRange")
259 }
260
261 // Children messages
262
263 #[proc_macro]
264 #[proc_macro_error]
children_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream265 pub fn children_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
266 let mut spans = input.into_iter().step_by(2).map(|s| s.span());
267 diagnostic!(spans.next().unwrap(), Level::Error, "main macro message")
268 .span_error(spans.next().unwrap().into(), "child message".into())
269 .emit();
270
271 let mut main = syn::Error::new(spans.next().unwrap().into(), "main syn::Error");
272 let child = syn::Error::new(spans.next().unwrap().into(), "child syn::Error");
273 main.combine(child);
274 Diagnostic::from(main).abort()
275 }
276