1#![allow(clippy::uninlined_format_args)] 2 3#[macro_use] 4mod macros; 5 6use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; 7use quote::quote; 8use syn::{Item, ItemTrait}; 9 10#[test] 11fn test_macro_variable_attr() { 12 // mimics the token stream corresponding to `$attr fn f() {}` 13 let tokens = TokenStream::from_iter(vec![ 14 TokenTree::Group(Group::new(Delimiter::None, quote! { #[test] })), 15 TokenTree::Ident(Ident::new("fn", Span::call_site())), 16 TokenTree::Ident(Ident::new("f", Span::call_site())), 17 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), 18 TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), 19 ]); 20 21 snapshot!(tokens as Item, @r###" 22 Item::Fn { 23 attrs: [ 24 Attribute { 25 style: AttrStyle::Outer, 26 meta: Meta::Path { 27 segments: [ 28 PathSegment { 29 ident: "test", 30 }, 31 ], 32 }, 33 }, 34 ], 35 vis: Visibility::Inherited, 36 sig: Signature { 37 ident: "f", 38 generics: Generics, 39 output: ReturnType::Default, 40 }, 41 block: Block { 42 stmts: [], 43 }, 44 } 45 "###); 46} 47 48#[test] 49fn test_negative_impl() { 50 // Rustc parses all of the following. 51 52 #[cfg(any())] 53 impl ! {} 54 let tokens = quote! { 55 impl ! {} 56 }; 57 snapshot!(tokens as Item, @r###" 58 Item::Impl { 59 generics: Generics, 60 self_ty: Type::Never, 61 } 62 "###); 63 64 #[cfg(any())] 65 #[rustfmt::skip] 66 impl !Trait {} 67 let tokens = quote! { 68 impl !Trait {} 69 }; 70 snapshot!(tokens as Item, @r###" 71 Item::Impl { 72 generics: Generics, 73 self_ty: Type::Verbatim(`! Trait`), 74 } 75 "###); 76 77 #[cfg(any())] 78 impl !Trait for T {} 79 let tokens = quote! { 80 impl !Trait for T {} 81 }; 82 snapshot!(tokens as Item, @r###" 83 Item::Impl { 84 generics: Generics, 85 trait_: Some(( 86 Some, 87 Path { 88 segments: [ 89 PathSegment { 90 ident: "Trait", 91 }, 92 ], 93 }, 94 )), 95 self_ty: Type::Path { 96 path: Path { 97 segments: [ 98 PathSegment { 99 ident: "T", 100 }, 101 ], 102 }, 103 }, 104 } 105 "###); 106 107 #[cfg(any())] 108 #[rustfmt::skip] 109 impl !! {} 110 let tokens = quote! { 111 impl !! {} 112 }; 113 snapshot!(tokens as Item, @r###" 114 Item::Impl { 115 generics: Generics, 116 self_ty: Type::Verbatim(`! !`), 117 } 118 "###); 119} 120 121#[test] 122fn test_macro_variable_impl() { 123 // mimics the token stream corresponding to `impl $trait for $ty {}` 124 let tokens = TokenStream::from_iter(vec![ 125 TokenTree::Ident(Ident::new("impl", Span::call_site())), 126 TokenTree::Group(Group::new(Delimiter::None, quote!(Trait))), 127 TokenTree::Ident(Ident::new("for", Span::call_site())), 128 TokenTree::Group(Group::new(Delimiter::None, quote!(Type))), 129 TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), 130 ]); 131 132 snapshot!(tokens as Item, @r###" 133 Item::Impl { 134 generics: Generics, 135 trait_: Some(( 136 None, 137 Path { 138 segments: [ 139 PathSegment { 140 ident: "Trait", 141 }, 142 ], 143 }, 144 )), 145 self_ty: Type::Group { 146 elem: Type::Path { 147 path: Path { 148 segments: [ 149 PathSegment { 150 ident: "Type", 151 }, 152 ], 153 }, 154 }, 155 }, 156 } 157 "###); 158} 159 160#[test] 161fn test_supertraits() { 162 // Rustc parses all of the following. 163 164 #[rustfmt::skip] 165 let tokens = quote!(trait Trait where {}); 166 snapshot!(tokens as ItemTrait, @r###" 167 ItemTrait { 168 vis: Visibility::Inherited, 169 ident: "Trait", 170 generics: Generics { 171 where_clause: Some(WhereClause), 172 }, 173 } 174 "###); 175 176 #[rustfmt::skip] 177 let tokens = quote!(trait Trait: where {}); 178 snapshot!(tokens as ItemTrait, @r###" 179 ItemTrait { 180 vis: Visibility::Inherited, 181 ident: "Trait", 182 generics: Generics { 183 where_clause: Some(WhereClause), 184 }, 185 colon_token: Some, 186 } 187 "###); 188 189 #[rustfmt::skip] 190 let tokens = quote!(trait Trait: Sized where {}); 191 snapshot!(tokens as ItemTrait, @r###" 192 ItemTrait { 193 vis: Visibility::Inherited, 194 ident: "Trait", 195 generics: Generics { 196 where_clause: Some(WhereClause), 197 }, 198 colon_token: Some, 199 supertraits: [ 200 TypeParamBound::Trait(TraitBound { 201 path: Path { 202 segments: [ 203 PathSegment { 204 ident: "Sized", 205 }, 206 ], 207 }, 208 }), 209 ], 210 } 211 "###); 212 213 #[rustfmt::skip] 214 let tokens = quote!(trait Trait: Sized + where {}); 215 snapshot!(tokens as ItemTrait, @r###" 216 ItemTrait { 217 vis: Visibility::Inherited, 218 ident: "Trait", 219 generics: Generics { 220 where_clause: Some(WhereClause), 221 }, 222 colon_token: Some, 223 supertraits: [ 224 TypeParamBound::Trait(TraitBound { 225 path: Path { 226 segments: [ 227 PathSegment { 228 ident: "Sized", 229 }, 230 ], 231 }, 232 }), 233 Token![+], 234 ], 235 } 236 "###); 237} 238 239#[test] 240fn test_type_empty_bounds() { 241 #[rustfmt::skip] 242 let tokens = quote! { 243 trait Foo { 244 type Bar: ; 245 } 246 }; 247 248 snapshot!(tokens as ItemTrait, @r###" 249 ItemTrait { 250 vis: Visibility::Inherited, 251 ident: "Foo", 252 generics: Generics, 253 items: [ 254 TraitItem::Type { 255 ident: "Bar", 256 generics: Generics, 257 colon_token: Some, 258 }, 259 ], 260 } 261 "###); 262} 263 264#[test] 265fn test_impl_visibility() { 266 let tokens = quote! { 267 pub default unsafe impl union {} 268 }; 269 270 snapshot!(tokens as Item, @"Item::Verbatim(`pub default unsafe impl union { }`)"); 271} 272 273#[test] 274fn test_impl_type_parameter_defaults() { 275 #[cfg(any())] 276 impl<T = ()> () {} 277 let tokens = quote! { 278 impl<T = ()> () {} 279 }; 280 snapshot!(tokens as Item, @r###" 281 Item::Impl { 282 generics: Generics { 283 lt_token: Some, 284 params: [ 285 GenericParam::Type(TypeParam { 286 ident: "T", 287 eq_token: Some, 288 default: Some(Type::Tuple), 289 }), 290 ], 291 gt_token: Some, 292 }, 293 self_ty: Type::Tuple, 294 } 295 "###); 296} 297 298#[test] 299fn test_impl_trait_trailing_plus() { 300 let tokens = quote! { 301 fn f() -> impl Sized + {} 302 }; 303 304 snapshot!(tokens as Item, @r###" 305 Item::Fn { 306 vis: Visibility::Inherited, 307 sig: Signature { 308 ident: "f", 309 generics: Generics, 310 output: ReturnType::Type( 311 Type::ImplTrait { 312 bounds: [ 313 TypeParamBound::Trait(TraitBound { 314 path: Path { 315 segments: [ 316 PathSegment { 317 ident: "Sized", 318 }, 319 ], 320 }, 321 }), 322 Token![+], 323 ], 324 }, 325 ), 326 }, 327 block: Block { 328 stmts: [], 329 }, 330 } 331 "###); 332} 333