1 | #![allow (clippy::uninlined_format_args)] |
2 | |
3 | #[macro_use ] |
4 | mod macros; |
5 | |
6 | use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; |
7 | use quote::{quote, ToTokens}; |
8 | use syn::{parse_quote, Expr, Type, TypePath}; |
9 | |
10 | #[test] |
11 | fn parse_interpolated_leading_component() { |
12 | // mimics the token stream corresponding to `$mod::rest` |
13 | let tokens = TokenStream::from_iter(vec![ |
14 | TokenTree::Group(Group::new(Delimiter::None, quote! { first })), |
15 | TokenTree::Punct(Punct::new(':' , Spacing::Joint)), |
16 | TokenTree::Punct(Punct::new(':' , Spacing::Alone)), |
17 | TokenTree::Ident(Ident::new("rest" , Span::call_site())), |
18 | ]); |
19 | |
20 | snapshot!(tokens.clone() as Expr, @r###" |
21 | Expr::Path { |
22 | path: Path { |
23 | segments: [ |
24 | PathSegment { |
25 | ident: "first", |
26 | }, |
27 | PathSegment { |
28 | ident: "rest", |
29 | }, |
30 | ], |
31 | }, |
32 | } |
33 | "### ); |
34 | |
35 | snapshot!(tokens as Type, @r###" |
36 | Type::Path { |
37 | path: Path { |
38 | segments: [ |
39 | PathSegment { |
40 | ident: "first", |
41 | }, |
42 | PathSegment { |
43 | ident: "rest", |
44 | }, |
45 | ], |
46 | }, |
47 | } |
48 | "### ); |
49 | } |
50 | |
51 | #[test] |
52 | fn print_incomplete_qpath() { |
53 | // qpath with `as` token |
54 | let mut ty: TypePath = parse_quote!(<Self as A>::Q); |
55 | snapshot!(ty.to_token_stream(), @r###" |
56 | TokenStream(`< Self as A > :: Q`) |
57 | "### ); |
58 | assert!(ty.path.segments.pop().is_some()); |
59 | snapshot!(ty.to_token_stream(), @r###" |
60 | TokenStream(`< Self as A > ::`) |
61 | "### ); |
62 | assert!(ty.path.segments.pop().is_some()); |
63 | snapshot!(ty.to_token_stream(), @r###" |
64 | TokenStream(`< Self >`) |
65 | "### ); |
66 | assert!(ty.path.segments.pop().is_none()); |
67 | |
68 | // qpath without `as` token |
69 | let mut ty: TypePath = parse_quote!(<Self>::A::B); |
70 | snapshot!(ty.to_token_stream(), @r###" |
71 | TokenStream(`< Self > :: A :: B`) |
72 | "### ); |
73 | assert!(ty.path.segments.pop().is_some()); |
74 | snapshot!(ty.to_token_stream(), @r###" |
75 | TokenStream(`< Self > :: A ::`) |
76 | "### ); |
77 | assert!(ty.path.segments.pop().is_some()); |
78 | snapshot!(ty.to_token_stream(), @r###" |
79 | TokenStream(`< Self > ::`) |
80 | "### ); |
81 | assert!(ty.path.segments.pop().is_none()); |
82 | |
83 | // normal path |
84 | let mut ty: TypePath = parse_quote!(Self::A::B); |
85 | snapshot!(ty.to_token_stream(), @r###" |
86 | TokenStream(`Self :: A :: B`) |
87 | "### ); |
88 | assert!(ty.path.segments.pop().is_some()); |
89 | snapshot!(ty.to_token_stream(), @r###" |
90 | TokenStream(`Self :: A ::`) |
91 | "### ); |
92 | assert!(ty.path.segments.pop().is_some()); |
93 | snapshot!(ty.to_token_stream(), @r###" |
94 | TokenStream(`Self ::`) |
95 | "### ); |
96 | assert!(ty.path.segments.pop().is_some()); |
97 | snapshot!(ty.to_token_stream(), @r###" |
98 | TokenStream(``) |
99 | "### ); |
100 | assert!(ty.path.segments.pop().is_none()); |
101 | } |
102 | |
103 | #[test] |
104 | fn parse_parenthesized_path_arguments_with_disambiguator() { |
105 | #[rustfmt::skip] |
106 | let tokens = quote!(dyn FnOnce::() -> !); |
107 | snapshot!(tokens as Type, @r###" |
108 | Type::TraitObject { |
109 | dyn_token: Some, |
110 | bounds: [ |
111 | TypeParamBound::Trait(TraitBound { |
112 | path: Path { |
113 | segments: [ |
114 | PathSegment { |
115 | ident: "FnOnce", |
116 | arguments: PathArguments::Parenthesized { |
117 | output: ReturnType::Type( |
118 | Type::Never, |
119 | ), |
120 | }, |
121 | }, |
122 | ], |
123 | }, |
124 | }), |
125 | ], |
126 | } |
127 | "### ); |
128 | } |
129 | |