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