1#![allow(clippy::non_ascii_literal)]
2
3use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
4use syn::parse::discouraged::Speculative as _;
5use syn::parse::{Parse, ParseStream, Parser, Result};
6use syn::{parenthesized, Token};
7
8#[test]
9#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
10fn smuggled_speculative_cursor_between_sources() {
11    struct BreakRules;
12    impl Parse for BreakRules {
13        fn parse(input1: ParseStream) -> Result<Self> {
14            let nested = |input2: ParseStream| {
15                input1.advance_to(input2);
16                Ok(Self)
17            };
18            nested.parse_str("")
19        }
20    }
21
22    syn::parse_str::<BreakRules>("").unwrap();
23}
24
25#[test]
26#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
27fn smuggled_speculative_cursor_between_brackets() {
28    struct BreakRules;
29    impl Parse for BreakRules {
30        fn parse(input: ParseStream) -> Result<Self> {
31            let a;
32            let b;
33            parenthesized!(a in input);
34            parenthesized!(b in input);
35            a.advance_to(&b);
36            Ok(Self)
37        }
38    }
39
40    syn::parse_str::<BreakRules>("()()").unwrap();
41}
42
43#[test]
44#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
45fn smuggled_speculative_cursor_into_brackets() {
46    struct BreakRules;
47    impl Parse for BreakRules {
48        fn parse(input: ParseStream) -> Result<Self> {
49            let a;
50            parenthesized!(a in input);
51            input.advance_to(&a);
52            Ok(Self)
53        }
54    }
55
56    syn::parse_str::<BreakRules>("()").unwrap();
57}
58
59#[test]
60fn trailing_empty_none_group() {
61    fn parse(input: ParseStream) -> Result<()> {
62        input.parse::<Token![+]>()?;
63
64        let content;
65        parenthesized!(content in input);
66        content.parse::<Token![+]>()?;
67
68        Ok(())
69    }
70
71    // `+ ( + <Ø Ø> ) <Ø <Ø Ø> Ø>`
72    let tokens = TokenStream::from_iter(vec![
73        TokenTree::Punct(Punct::new('+', Spacing::Alone)),
74        TokenTree::Group(Group::new(
75            Delimiter::Parenthesis,
76            TokenStream::from_iter(vec![
77                TokenTree::Punct(Punct::new('+', Spacing::Alone)),
78                TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
79            ]),
80        )),
81        TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
82        TokenTree::Group(Group::new(
83            Delimiter::None,
84            TokenStream::from_iter(vec![TokenTree::Group(Group::new(
85                Delimiter::None,
86                TokenStream::new(),
87            ))]),
88        )),
89    ]);
90
91    parse.parse2(tokens).unwrap();
92}
93