1#[macro_use]
2extern crate proc_macro_error;
3extern crate proc_macro;
4
5use proc_macro2::{Span, TokenStream};
6use 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
11use syn::{parse_macro_input, spanned::Spanned};
12
13// Macros and Diagnostic
14
15#[proc_macro]
16#[proc_macro_error]
17pub 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]
27pub 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]
34pub 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]
41pub 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]
47pub 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]
54pub 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]
86pub 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]
116pub 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]
148pub 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]
156pub 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]
170pub 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]
186pub 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]
199pub 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]
218pub 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]
226pub 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]
235pub 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]
245pub 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]
254pub 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]
265pub 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