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