test_expr.rs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #[macro_use]
  2. mod macros;
  3. use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
  4. use quote::quote;
  5. use std::iter::FromIterator;
  6. use syn::{Expr, ExprRange};
  7. #[test]
  8. fn test_expr_parse() {
  9. let tokens = quote!(..100u32);
  10. snapshot!(tokens as Expr, @r###"
  11. Expr::Range {
  12. limits: HalfOpen,
  13. to: Some(Expr::Lit {
  14. lit: 100u32,
  15. }),
  16. }
  17. "###);
  18. let tokens = quote!(..100u32);
  19. snapshot!(tokens as ExprRange, @r###"
  20. ExprRange {
  21. limits: HalfOpen,
  22. to: Some(Expr::Lit {
  23. lit: 100u32,
  24. }),
  25. }
  26. "###);
  27. }
  28. #[test]
  29. fn test_await() {
  30. // Must not parse as Expr::Field.
  31. let tokens = quote!(fut.await);
  32. snapshot!(tokens as Expr, @r###"
  33. Expr::Await {
  34. base: Expr::Path {
  35. path: Path {
  36. segments: [
  37. PathSegment {
  38. ident: "fut",
  39. arguments: None,
  40. },
  41. ],
  42. },
  43. },
  44. }
  45. "###);
  46. }
  47. #[rustfmt::skip]
  48. #[test]
  49. fn test_tuple_multi_index() {
  50. for &input in &[
  51. "tuple.0.0",
  52. "tuple .0.0",
  53. "tuple. 0.0",
  54. "tuple.0 .0",
  55. "tuple.0. 0",
  56. "tuple . 0 . 0",
  57. ] {
  58. snapshot!(input as Expr, @r###"
  59. Expr::Field {
  60. base: Expr::Field {
  61. base: Expr::Path {
  62. path: Path {
  63. segments: [
  64. PathSegment {
  65. ident: "tuple",
  66. arguments: None,
  67. },
  68. ],
  69. },
  70. },
  71. member: Unnamed(Index {
  72. index: 0,
  73. }),
  74. },
  75. member: Unnamed(Index {
  76. index: 0,
  77. }),
  78. }
  79. "###);
  80. }
  81. for tokens in vec![
  82. quote!(tuple.0.0),
  83. quote!(tuple .0.0),
  84. quote!(tuple. 0.0),
  85. quote!(tuple.0 .0),
  86. quote!(tuple.0. 0),
  87. quote!(tuple . 0 . 0),
  88. ] {
  89. snapshot!(tokens as Expr, @r###"
  90. Expr::Field {
  91. base: Expr::Field {
  92. base: Expr::Path {
  93. path: Path {
  94. segments: [
  95. PathSegment {
  96. ident: "tuple",
  97. arguments: None,
  98. },
  99. ],
  100. },
  101. },
  102. member: Unnamed(Index {
  103. index: 0,
  104. }),
  105. },
  106. member: Unnamed(Index {
  107. index: 0,
  108. }),
  109. }
  110. "###);
  111. }
  112. }
  113. #[test]
  114. fn test_macro_variable_func() {
  115. // mimics the token stream corresponding to `$fn()`
  116. let tokens = TokenStream::from_iter(vec![
  117. TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
  118. TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
  119. ]);
  120. snapshot!(tokens as Expr, @r###"
  121. Expr::Call {
  122. func: Expr::Group {
  123. expr: Expr::Path {
  124. path: Path {
  125. segments: [
  126. PathSegment {
  127. ident: "f",
  128. arguments: None,
  129. },
  130. ],
  131. },
  132. },
  133. },
  134. }
  135. "###);
  136. let tokens = TokenStream::from_iter(vec![
  137. TokenTree::Punct(Punct::new('#', Spacing::Alone)),
  138. TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
  139. TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
  140. TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
  141. ]);
  142. snapshot!(tokens as Expr, @r###"
  143. Expr::Call {
  144. attrs: [
  145. Attribute {
  146. style: Outer,
  147. path: Path {
  148. segments: [
  149. PathSegment {
  150. ident: "outside",
  151. arguments: None,
  152. },
  153. ],
  154. },
  155. tokens: TokenStream(``),
  156. },
  157. ],
  158. func: Expr::Group {
  159. expr: Expr::Path {
  160. attrs: [
  161. Attribute {
  162. style: Outer,
  163. path: Path {
  164. segments: [
  165. PathSegment {
  166. ident: "inside",
  167. arguments: None,
  168. },
  169. ],
  170. },
  171. tokens: TokenStream(``),
  172. },
  173. ],
  174. path: Path {
  175. segments: [
  176. PathSegment {
  177. ident: "f",
  178. arguments: None,
  179. },
  180. ],
  181. },
  182. },
  183. },
  184. }
  185. "###);
  186. }
  187. #[test]
  188. fn test_macro_variable_macro() {
  189. // mimics the token stream corresponding to `$macro!()`
  190. let tokens = TokenStream::from_iter(vec![
  191. TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
  192. TokenTree::Punct(Punct::new('!', Spacing::Alone)),
  193. TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
  194. ]);
  195. snapshot!(tokens as Expr, @r###"
  196. Expr::Macro {
  197. mac: Macro {
  198. path: Path {
  199. segments: [
  200. PathSegment {
  201. ident: "m",
  202. arguments: None,
  203. },
  204. ],
  205. },
  206. delimiter: Paren,
  207. tokens: TokenStream(``),
  208. },
  209. }
  210. "###);
  211. }
  212. #[test]
  213. fn test_macro_variable_struct() {
  214. // mimics the token stream corresponding to `$struct {}`
  215. let tokens = TokenStream::from_iter(vec![
  216. TokenTree::Group(Group::new(Delimiter::None, quote! { S })),
  217. TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
  218. ]);
  219. snapshot!(tokens as Expr, @r###"
  220. Expr::Struct {
  221. path: Path {
  222. segments: [
  223. PathSegment {
  224. ident: "S",
  225. arguments: None,
  226. },
  227. ],
  228. },
  229. }
  230. "###);
  231. }
  232. #[test]
  233. fn test_macro_variable_match_arm() {
  234. // mimics the token stream corresponding to `match v { _ => $expr }`
  235. let tokens = TokenStream::from_iter(vec![
  236. TokenTree::Ident(Ident::new("match", Span::call_site())),
  237. TokenTree::Ident(Ident::new("v", Span::call_site())),
  238. TokenTree::Group(Group::new(
  239. Delimiter::Brace,
  240. TokenStream::from_iter(vec![
  241. TokenTree::Punct(Punct::new('_', Spacing::Alone)),
  242. TokenTree::Punct(Punct::new('=', Spacing::Joint)),
  243. TokenTree::Punct(Punct::new('>', Spacing::Alone)),
  244. TokenTree::Group(Group::new(Delimiter::None, quote! { #[a] () })),
  245. ]),
  246. )),
  247. ]);
  248. snapshot!(tokens as Expr, @r###"
  249. Expr::Match {
  250. expr: Expr::Path {
  251. path: Path {
  252. segments: [
  253. PathSegment {
  254. ident: "v",
  255. arguments: None,
  256. },
  257. ],
  258. },
  259. },
  260. arms: [
  261. Arm {
  262. pat: Pat::Wild,
  263. body: Expr::Group {
  264. expr: Expr::Tuple {
  265. attrs: [
  266. Attribute {
  267. style: Outer,
  268. path: Path {
  269. segments: [
  270. PathSegment {
  271. ident: "a",
  272. arguments: None,
  273. },
  274. ],
  275. },
  276. tokens: TokenStream(``),
  277. },
  278. ],
  279. },
  280. },
  281. },
  282. ],
  283. }
  284. "###);
  285. }
  286. // https://github.com/dtolnay/syn/issues/1019
  287. #[test]
  288. fn test_closure_vs_rangefull() {
  289. #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808
  290. let tokens = quote!(|| .. .method());
  291. snapshot!(tokens as Expr, @r###"
  292. Expr::MethodCall {
  293. receiver: Expr::Closure {
  294. output: Default,
  295. body: Expr::Range {
  296. limits: HalfOpen,
  297. },
  298. },
  299. method: "method",
  300. }
  301. "###);
  302. }
  303. #[test]
  304. fn test_postfix_operator_after_cast() {
  305. syn::parse_str::<Expr>("|| &x as T[0]").unwrap_err();
  306. syn::parse_str::<Expr>("|| () as ()()").unwrap_err();
  307. }