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