xref: /third_party/rust/crates/syn/tests/test_item.rs (revision fad3a1d3)
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