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