| 1 | #![allow (clippy::uninlined_format_args)] |
| 2 | |
| 3 | #[macro_use ] |
| 4 | mod macros; |
| 5 | |
| 6 | use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; |
| 7 | use quote::quote; |
| 8 | use syn::{Item, ItemTrait}; |
| 9 | |
| 10 | #[test] |
| 11 | fn 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] |
| 49 | fn 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] |
| 122 | fn 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] |
| 161 | fn 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 | ], |
| 234 | } |
| 235 | "### ); |
| 236 | } |
| 237 | |
| 238 | #[test] |
| 239 | fn test_type_empty_bounds() { |
| 240 | #[rustfmt::skip] |
| 241 | let tokens = quote! { |
| 242 | trait Foo { |
| 243 | type Bar: ; |
| 244 | } |
| 245 | }; |
| 246 | |
| 247 | snapshot!(tokens as ItemTrait, @r###" |
| 248 | ItemTrait { |
| 249 | vis: Visibility::Inherited, |
| 250 | ident: "Foo", |
| 251 | generics: Generics, |
| 252 | items: [ |
| 253 | TraitItem::Type { |
| 254 | ident: "Bar", |
| 255 | generics: Generics, |
| 256 | colon_token: Some, |
| 257 | }, |
| 258 | ], |
| 259 | } |
| 260 | "### ); |
| 261 | } |
| 262 | |
| 263 | #[test] |
| 264 | fn test_impl_visibility() { |
| 265 | let tokens = quote! { |
| 266 | pub default unsafe impl union {} |
| 267 | }; |
| 268 | |
| 269 | snapshot!(tokens as Item, @"Item::Verbatim(`pub default unsafe impl union { }`)" ); |
| 270 | } |
| 271 | |
| 272 | #[test] |
| 273 | fn test_impl_type_parameter_defaults() { |
| 274 | #[cfg (any())] |
| 275 | impl<T = ()> () {} |
| 276 | let tokens = quote! { |
| 277 | impl<T = ()> () {} |
| 278 | }; |
| 279 | snapshot!(tokens as Item, @r###" |
| 280 | Item::Impl { |
| 281 | generics: Generics { |
| 282 | lt_token: Some, |
| 283 | params: [ |
| 284 | GenericParam::Type(TypeParam { |
| 285 | ident: "T", |
| 286 | eq_token: Some, |
| 287 | default: Some(Type::Tuple), |
| 288 | }), |
| 289 | ], |
| 290 | gt_token: Some, |
| 291 | }, |
| 292 | self_ty: Type::Tuple, |
| 293 | } |
| 294 | "### ); |
| 295 | } |
| 296 | |
| 297 | #[test] |
| 298 | fn test_impl_trait_trailing_plus() { |
| 299 | let tokens = quote! { |
| 300 | fn f() -> impl Sized + {} |
| 301 | }; |
| 302 | |
| 303 | snapshot!(tokens as Item, @r###" |
| 304 | Item::Fn { |
| 305 | vis: Visibility::Inherited, |
| 306 | sig: Signature { |
| 307 | ident: "f", |
| 308 | generics: Generics, |
| 309 | output: ReturnType::Type( |
| 310 | Type::ImplTrait { |
| 311 | bounds: [ |
| 312 | TypeParamBound::Trait(TraitBound { |
| 313 | path: Path { |
| 314 | segments: [ |
| 315 | PathSegment { |
| 316 | ident: "Sized", |
| 317 | }, |
| 318 | ], |
| 319 | }, |
| 320 | }), |
| 321 | ], |
| 322 | }, |
| 323 | ), |
| 324 | }, |
| 325 | block: Block { |
| 326 | stmts: [], |
| 327 | }, |
| 328 | } |
| 329 | "### ); |
| 330 | } |
| 331 | |