• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(
2     clippy::assertions_on_result_states,
3     clippy::elidable_lifetime_names,
4     clippy::manual_let_else,
5     clippy::needless_lifetimes,
6     clippy::too_many_lines,
7     clippy::uninlined_format_args
8 )]
9 
10 #[macro_use]
11 mod macros;
12 
13 use quote::quote;
14 use syn::{Data, DeriveInput};
15 
16 #[test]
test_unit()17 fn test_unit() {
18     let input = quote! {
19         struct Unit;
20     };
21 
22     snapshot!(input as DeriveInput, @r#"
23     DeriveInput {
24         vis: Visibility::Inherited,
25         ident: "Unit",
26         generics: Generics,
27         data: Data::Struct {
28             fields: Fields::Unit,
29             semi_token: Some,
30         },
31     }
32     "#);
33 }
34 
35 #[test]
test_struct()36 fn test_struct() {
37     let input = quote! {
38         #[derive(Debug, Clone)]
39         pub struct Item {
40             pub ident: Ident,
41             pub attrs: Vec<Attribute>
42         }
43     };
44 
45     snapshot!(input as DeriveInput, @r#"
46     DeriveInput {
47         attrs: [
48             Attribute {
49                 style: AttrStyle::Outer,
50                 meta: Meta::List {
51                     path: Path {
52                         segments: [
53                             PathSegment {
54                                 ident: "derive",
55                             },
56                         ],
57                     },
58                     delimiter: MacroDelimiter::Paren,
59                     tokens: TokenStream(`Debug , Clone`),
60                 },
61             },
62         ],
63         vis: Visibility::Public,
64         ident: "Item",
65         generics: Generics,
66         data: Data::Struct {
67             fields: Fields::Named {
68                 named: [
69                     Field {
70                         vis: Visibility::Public,
71                         ident: Some("ident"),
72                         colon_token: Some,
73                         ty: Type::Path {
74                             path: Path {
75                                 segments: [
76                                     PathSegment {
77                                         ident: "Ident",
78                                     },
79                                 ],
80                             },
81                         },
82                     },
83                     Token![,],
84                     Field {
85                         vis: Visibility::Public,
86                         ident: Some("attrs"),
87                         colon_token: Some,
88                         ty: Type::Path {
89                             path: Path {
90                                 segments: [
91                                     PathSegment {
92                                         ident: "Vec",
93                                         arguments: PathArguments::AngleBracketed {
94                                             args: [
95                                                 GenericArgument::Type(Type::Path {
96                                                     path: Path {
97                                                         segments: [
98                                                             PathSegment {
99                                                                 ident: "Attribute",
100                                                             },
101                                                         ],
102                                                     },
103                                                 }),
104                                             ],
105                                         },
106                                     },
107                                 ],
108                             },
109                         },
110                     },
111                 ],
112             },
113         },
114     }
115     "#);
116 
117     snapshot!(&input.attrs[0].meta, @r#"
118     Meta::List {
119         path: Path {
120             segments: [
121                 PathSegment {
122                     ident: "derive",
123                 },
124             ],
125         },
126         delimiter: MacroDelimiter::Paren,
127         tokens: TokenStream(`Debug , Clone`),
128     }
129     "#);
130 }
131 
132 #[test]
test_union()133 fn test_union() {
134     let input = quote! {
135         union MaybeUninit<T> {
136             uninit: (),
137             value: T
138         }
139     };
140 
141     snapshot!(input as DeriveInput, @r#"
142     DeriveInput {
143         vis: Visibility::Inherited,
144         ident: "MaybeUninit",
145         generics: Generics {
146             lt_token: Some,
147             params: [
148                 GenericParam::Type(TypeParam {
149                     ident: "T",
150                 }),
151             ],
152             gt_token: Some,
153         },
154         data: Data::Union {
155             fields: FieldsNamed {
156                 named: [
157                     Field {
158                         vis: Visibility::Inherited,
159                         ident: Some("uninit"),
160                         colon_token: Some,
161                         ty: Type::Tuple,
162                     },
163                     Token![,],
164                     Field {
165                         vis: Visibility::Inherited,
166                         ident: Some("value"),
167                         colon_token: Some,
168                         ty: Type::Path {
169                             path: Path {
170                                 segments: [
171                                     PathSegment {
172                                         ident: "T",
173                                     },
174                                 ],
175                             },
176                         },
177                     },
178                 ],
179             },
180         },
181     }
182     "#);
183 }
184 
185 #[test]
186 #[cfg(feature = "full")]
test_enum()187 fn test_enum() {
188     let input = quote! {
189         /// See the std::result module documentation for details.
190         #[must_use]
191         pub enum Result<T, E> {
192             Ok(T),
193             Err(E),
194             Surprise = 0isize,
195 
196             // Smuggling data into a proc_macro_derive,
197             // in the style of https://github.com/dtolnay/proc-macro-hack
198             ProcMacroHack = (0, "data").0
199         }
200     };
201 
202     snapshot!(input as DeriveInput, @r#"
203     DeriveInput {
204         attrs: [
205             Attribute {
206                 style: AttrStyle::Outer,
207                 meta: Meta::NameValue {
208                     path: Path {
209                         segments: [
210                             PathSegment {
211                                 ident: "doc",
212                             },
213                         ],
214                     },
215                     value: Expr::Lit {
216                         lit: " See the std::result module documentation for details.",
217                     },
218                 },
219             },
220             Attribute {
221                 style: AttrStyle::Outer,
222                 meta: Meta::Path {
223                     segments: [
224                         PathSegment {
225                             ident: "must_use",
226                         },
227                     ],
228                 },
229             },
230         ],
231         vis: Visibility::Public,
232         ident: "Result",
233         generics: Generics {
234             lt_token: Some,
235             params: [
236                 GenericParam::Type(TypeParam {
237                     ident: "T",
238                 }),
239                 Token![,],
240                 GenericParam::Type(TypeParam {
241                     ident: "E",
242                 }),
243             ],
244             gt_token: Some,
245         },
246         data: Data::Enum {
247             variants: [
248                 Variant {
249                     ident: "Ok",
250                     fields: Fields::Unnamed {
251                         unnamed: [
252                             Field {
253                                 vis: Visibility::Inherited,
254                                 ty: Type::Path {
255                                     path: Path {
256                                         segments: [
257                                             PathSegment {
258                                                 ident: "T",
259                                             },
260                                         ],
261                                     },
262                                 },
263                             },
264                         ],
265                     },
266                 },
267                 Token![,],
268                 Variant {
269                     ident: "Err",
270                     fields: Fields::Unnamed {
271                         unnamed: [
272                             Field {
273                                 vis: Visibility::Inherited,
274                                 ty: Type::Path {
275                                     path: Path {
276                                         segments: [
277                                             PathSegment {
278                                                 ident: "E",
279                                             },
280                                         ],
281                                     },
282                                 },
283                             },
284                         ],
285                     },
286                 },
287                 Token![,],
288                 Variant {
289                     ident: "Surprise",
290                     fields: Fields::Unit,
291                     discriminant: Some(Expr::Lit {
292                         lit: 0isize,
293                     }),
294                 },
295                 Token![,],
296                 Variant {
297                     ident: "ProcMacroHack",
298                     fields: Fields::Unit,
299                     discriminant: Some(Expr::Field {
300                         base: Expr::Tuple {
301                             elems: [
302                                 Expr::Lit {
303                                     lit: 0,
304                                 },
305                                 Token![,],
306                                 Expr::Lit {
307                                     lit: "data",
308                                 },
309                             ],
310                         },
311                         member: Member::Unnamed(Index {
312                             index: 0,
313                         }),
314                     }),
315                 },
316             ],
317         },
318     }
319     "#);
320 
321     let meta_items: Vec<_> = input.attrs.into_iter().map(|attr| attr.meta).collect();
322 
323     snapshot!(meta_items, @r#"
324     [
325         Meta::NameValue {
326             path: Path {
327                 segments: [
328                     PathSegment {
329                         ident: "doc",
330                     },
331                 ],
332             },
333             value: Expr::Lit {
334                 lit: " See the std::result module documentation for details.",
335             },
336         },
337         Meta::Path {
338             segments: [
339                 PathSegment {
340                     ident: "must_use",
341                 },
342             ],
343         },
344     ]
345     "#);
346 }
347 
348 #[test]
test_attr_with_non_mod_style_path()349 fn test_attr_with_non_mod_style_path() {
350     let input = quote! {
351         #[inert <T>]
352         struct S;
353     };
354 
355     syn::parse2::<DeriveInput>(input).unwrap_err();
356 }
357 
358 #[test]
test_attr_with_mod_style_path_with_self()359 fn test_attr_with_mod_style_path_with_self() {
360     let input = quote! {
361         #[foo::self]
362         struct S;
363     };
364 
365     snapshot!(input as DeriveInput, @r#"
366     DeriveInput {
367         attrs: [
368             Attribute {
369                 style: AttrStyle::Outer,
370                 meta: Meta::Path {
371                     segments: [
372                         PathSegment {
373                             ident: "foo",
374                         },
375                         Token![::],
376                         PathSegment {
377                             ident: "self",
378                         },
379                     ],
380                 },
381             },
382         ],
383         vis: Visibility::Inherited,
384         ident: "S",
385         generics: Generics,
386         data: Data::Struct {
387             fields: Fields::Unit,
388             semi_token: Some,
389         },
390     }
391     "#);
392 
393     snapshot!(&input.attrs[0].meta, @r#"
394     Meta::Path {
395         segments: [
396             PathSegment {
397                 ident: "foo",
398             },
399             Token![::],
400             PathSegment {
401                 ident: "self",
402             },
403         ],
404     }
405     "#);
406 }
407 
408 #[test]
test_pub_restricted()409 fn test_pub_restricted() {
410     // Taken from tests/rust/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs
411     let input = quote! {
412         pub(in m) struct Z(pub(in m::n) u8);
413     };
414 
415     snapshot!(input as DeriveInput, @r#"
416     DeriveInput {
417         vis: Visibility::Restricted {
418             in_token: Some,
419             path: Path {
420                 segments: [
421                     PathSegment {
422                         ident: "m",
423                     },
424                 ],
425             },
426         },
427         ident: "Z",
428         generics: Generics,
429         data: Data::Struct {
430             fields: Fields::Unnamed {
431                 unnamed: [
432                     Field {
433                         vis: Visibility::Restricted {
434                             in_token: Some,
435                             path: Path {
436                                 segments: [
437                                     PathSegment {
438                                         ident: "m",
439                                     },
440                                     Token![::],
441                                     PathSegment {
442                                         ident: "n",
443                                     },
444                                 ],
445                             },
446                         },
447                         ty: Type::Path {
448                             path: Path {
449                                 segments: [
450                                     PathSegment {
451                                         ident: "u8",
452                                     },
453                                 ],
454                             },
455                         },
456                     },
457                 ],
458             },
459             semi_token: Some,
460         },
461     }
462     "#);
463 }
464 
465 #[test]
test_pub_restricted_crate()466 fn test_pub_restricted_crate() {
467     let input = quote! {
468         pub(crate) struct S;
469     };
470 
471     snapshot!(input as DeriveInput, @r#"
472     DeriveInput {
473         vis: Visibility::Restricted {
474             path: Path {
475                 segments: [
476                     PathSegment {
477                         ident: "crate",
478                     },
479                 ],
480             },
481         },
482         ident: "S",
483         generics: Generics,
484         data: Data::Struct {
485             fields: Fields::Unit,
486             semi_token: Some,
487         },
488     }
489     "#);
490 }
491 
492 #[test]
test_pub_restricted_super()493 fn test_pub_restricted_super() {
494     let input = quote! {
495         pub(super) struct S;
496     };
497 
498     snapshot!(input as DeriveInput, @r#"
499     DeriveInput {
500         vis: Visibility::Restricted {
501             path: Path {
502                 segments: [
503                     PathSegment {
504                         ident: "super",
505                     },
506                 ],
507             },
508         },
509         ident: "S",
510         generics: Generics,
511         data: Data::Struct {
512             fields: Fields::Unit,
513             semi_token: Some,
514         },
515     }
516     "#);
517 }
518 
519 #[test]
test_pub_restricted_in_super()520 fn test_pub_restricted_in_super() {
521     let input = quote! {
522         pub(in super) struct S;
523     };
524 
525     snapshot!(input as DeriveInput, @r#"
526     DeriveInput {
527         vis: Visibility::Restricted {
528             in_token: Some,
529             path: Path {
530                 segments: [
531                     PathSegment {
532                         ident: "super",
533                     },
534                 ],
535             },
536         },
537         ident: "S",
538         generics: Generics,
539         data: Data::Struct {
540             fields: Fields::Unit,
541             semi_token: Some,
542         },
543     }
544     "#);
545 }
546 
547 #[test]
test_fields_on_unit_struct()548 fn test_fields_on_unit_struct() {
549     let input = quote! {
550         struct S;
551     };
552 
553     snapshot!(input as DeriveInput, @r#"
554     DeriveInput {
555         vis: Visibility::Inherited,
556         ident: "S",
557         generics: Generics,
558         data: Data::Struct {
559             fields: Fields::Unit,
560             semi_token: Some,
561         },
562     }
563     "#);
564 
565     let data = match input.data {
566         Data::Struct(data) => data,
567         _ => panic!("expected a struct"),
568     };
569 
570     assert_eq!(0, data.fields.iter().count());
571 }
572 
573 #[test]
test_fields_on_named_struct()574 fn test_fields_on_named_struct() {
575     let input = quote! {
576         struct S {
577             foo: i32,
578             pub bar: String,
579         }
580     };
581 
582     snapshot!(input as DeriveInput, @r#"
583     DeriveInput {
584         vis: Visibility::Inherited,
585         ident: "S",
586         generics: Generics,
587         data: Data::Struct {
588             fields: Fields::Named {
589                 named: [
590                     Field {
591                         vis: Visibility::Inherited,
592                         ident: Some("foo"),
593                         colon_token: Some,
594                         ty: Type::Path {
595                             path: Path {
596                                 segments: [
597                                     PathSegment {
598                                         ident: "i32",
599                                     },
600                                 ],
601                             },
602                         },
603                     },
604                     Token![,],
605                     Field {
606                         vis: Visibility::Public,
607                         ident: Some("bar"),
608                         colon_token: Some,
609                         ty: Type::Path {
610                             path: Path {
611                                 segments: [
612                                     PathSegment {
613                                         ident: "String",
614                                     },
615                                 ],
616                             },
617                         },
618                     },
619                     Token![,],
620                 ],
621             },
622         },
623     }
624     "#);
625 
626     let data = match input.data {
627         Data::Struct(data) => data,
628         _ => panic!("expected a struct"),
629     };
630 
631     snapshot!(data.fields.into_iter().collect::<Vec<_>>(), @r#"
632     [
633         Field {
634             vis: Visibility::Inherited,
635             ident: Some("foo"),
636             colon_token: Some,
637             ty: Type::Path {
638                 path: Path {
639                     segments: [
640                         PathSegment {
641                             ident: "i32",
642                         },
643                     ],
644                 },
645             },
646         },
647         Field {
648             vis: Visibility::Public,
649             ident: Some("bar"),
650             colon_token: Some,
651             ty: Type::Path {
652                 path: Path {
653                     segments: [
654                         PathSegment {
655                             ident: "String",
656                         },
657                     ],
658                 },
659             },
660         },
661     ]
662     "#);
663 }
664 
665 #[test]
test_fields_on_tuple_struct()666 fn test_fields_on_tuple_struct() {
667     let input = quote! {
668         struct S(i32, pub String);
669     };
670 
671     snapshot!(input as DeriveInput, @r#"
672     DeriveInput {
673         vis: Visibility::Inherited,
674         ident: "S",
675         generics: Generics,
676         data: Data::Struct {
677             fields: Fields::Unnamed {
678                 unnamed: [
679                     Field {
680                         vis: Visibility::Inherited,
681                         ty: Type::Path {
682                             path: Path {
683                                 segments: [
684                                     PathSegment {
685                                         ident: "i32",
686                                     },
687                                 ],
688                             },
689                         },
690                     },
691                     Token![,],
692                     Field {
693                         vis: Visibility::Public,
694                         ty: Type::Path {
695                             path: Path {
696                                 segments: [
697                                     PathSegment {
698                                         ident: "String",
699                                     },
700                                 ],
701                             },
702                         },
703                     },
704                 ],
705             },
706             semi_token: Some,
707         },
708     }
709     "#);
710 
711     let data = match input.data {
712         Data::Struct(data) => data,
713         _ => panic!("expected a struct"),
714     };
715 
716     snapshot!(data.fields.iter().collect::<Vec<_>>(), @r#"
717     [
718         Field {
719             vis: Visibility::Inherited,
720             ty: Type::Path {
721                 path: Path {
722                     segments: [
723                         PathSegment {
724                             ident: "i32",
725                         },
726                     ],
727                 },
728             },
729         },
730         Field {
731             vis: Visibility::Public,
732             ty: Type::Path {
733                 path: Path {
734                     segments: [
735                         PathSegment {
736                             ident: "String",
737                         },
738                     ],
739                 },
740             },
741         },
742     ]
743     "#);
744 }
745 
746 #[test]
test_ambiguous_crate()747 fn test_ambiguous_crate() {
748     let input = quote! {
749         // The field type is `(crate::X)` not `crate (::X)`.
750         struct S(crate::X);
751     };
752 
753     snapshot!(input as DeriveInput, @r#"
754     DeriveInput {
755         vis: Visibility::Inherited,
756         ident: "S",
757         generics: Generics,
758         data: Data::Struct {
759             fields: Fields::Unnamed {
760                 unnamed: [
761                     Field {
762                         vis: Visibility::Inherited,
763                         ty: Type::Path {
764                             path: Path {
765                                 segments: [
766                                     PathSegment {
767                                         ident: "crate",
768                                     },
769                                     Token![::],
770                                     PathSegment {
771                                         ident: "X",
772                                     },
773                                 ],
774                             },
775                         },
776                     },
777                 ],
778             },
779             semi_token: Some,
780         },
781     }
782     "#);
783 }
784