1#![allow(clippy::uninlined_format_args)] 2 3#[macro_use] 4mod macros; 5 6use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; 7use quote::{quote, ToTokens}; 8use syn::{parse_quote, Expr, Type, TypePath}; 9 10#[test] 11fn 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 Token![::], 28 PathSegment { 29 ident: "rest", 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 }, 43 Token![::], 44 PathSegment { 45 ident: "rest", 46 }, 47 ], 48 }, 49 } 50 "###); 51} 52 53#[test] 54fn print_incomplete_qpath() { 55 // qpath with `as` token 56 let mut ty: TypePath = parse_quote!(<Self as A>::Q); 57 snapshot!(ty.to_token_stream(), @r###" 58 TokenStream(`< Self as A > :: Q`) 59 "###); 60 assert!(ty.path.segments.pop().is_some()); 61 snapshot!(ty.to_token_stream(), @r###" 62 TokenStream(`< Self as A > ::`) 63 "###); 64 assert!(ty.path.segments.pop().is_some()); 65 snapshot!(ty.to_token_stream(), @r###" 66 TokenStream(`< Self >`) 67 "###); 68 assert!(ty.path.segments.pop().is_none()); 69 70 // qpath without `as` token 71 let mut ty: TypePath = parse_quote!(<Self>::A::B); 72 snapshot!(ty.to_token_stream(), @r###" 73 TokenStream(`< Self > :: A :: B`) 74 "###); 75 assert!(ty.path.segments.pop().is_some()); 76 snapshot!(ty.to_token_stream(), @r###" 77 TokenStream(`< Self > :: A ::`) 78 "###); 79 assert!(ty.path.segments.pop().is_some()); 80 snapshot!(ty.to_token_stream(), @r###" 81 TokenStream(`< Self > ::`) 82 "###); 83 assert!(ty.path.segments.pop().is_none()); 84 85 // normal path 86 let mut ty: TypePath = parse_quote!(Self::A::B); 87 snapshot!(ty.to_token_stream(), @r###" 88 TokenStream(`Self :: A :: B`) 89 "###); 90 assert!(ty.path.segments.pop().is_some()); 91 snapshot!(ty.to_token_stream(), @r###" 92 TokenStream(`Self :: A ::`) 93 "###); 94 assert!(ty.path.segments.pop().is_some()); 95 snapshot!(ty.to_token_stream(), @r###" 96 TokenStream(`Self ::`) 97 "###); 98 assert!(ty.path.segments.pop().is_some()); 99 snapshot!(ty.to_token_stream(), @r###" 100 TokenStream(``) 101 "###); 102 assert!(ty.path.segments.pop().is_none()); 103} 104 105#[test] 106fn parse_parenthesized_path_arguments_with_disambiguator() { 107 #[rustfmt::skip] 108 let tokens = quote!(dyn FnOnce::() -> !); 109 snapshot!(tokens as Type, @r###" 110 Type::TraitObject { 111 dyn_token: Some, 112 bounds: [ 113 TypeParamBound::Trait(TraitBound { 114 path: Path { 115 segments: [ 116 PathSegment { 117 ident: "FnOnce", 118 arguments: PathArguments::Parenthesized { 119 output: ReturnType::Type( 120 Type::Never, 121 ), 122 }, 123 }, 124 ], 125 }, 126 }), 127 ], 128 } 129 "###); 130} 131