xref: /third_party/rust/crates/syn/src/restriction.rs (revision fad3a1d3)
1use super::*;
2
3ast_enum! {
4    /// The visibility level of an item: inherited or `pub` or
5    /// `pub(restricted)`.
6    ///
7    /// # Syntax tree enum
8    ///
9    /// This type is a [syntax tree enum].
10    ///
11    /// [syntax tree enum]: Expr#syntax-tree-enums
12    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
13    pub enum Visibility {
14        /// A public visibility level: `pub`.
15        Public(Token![pub]),
16
17        /// A visibility level restricted to some path: `pub(self)` or
18        /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
19        Restricted(VisRestricted),
20
21        /// An inherited visibility, which usually means private.
22        Inherited,
23    }
24}
25
26ast_struct! {
27    /// A visibility level restricted to some path: `pub(self)` or
28    /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
29    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
30    pub struct VisRestricted {
31        pub pub_token: Token![pub],
32        pub paren_token: token::Paren,
33        pub in_token: Option<Token![in]>,
34        pub path: Box<Path>,
35    }
36}
37
38ast_enum! {
39    /// Unused, but reserved for RFC 3323 restrictions.
40    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
41    #[non_exhaustive]
42    pub enum FieldMutability {
43        None,
44
45        // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html
46        //
47        // FieldMutability::Restricted(MutRestricted)
48        //
49        // pub struct MutRestricted {
50        //     pub mut_token: Token![mut],
51        //     pub paren_token: token::Paren,
52        //     pub in_token: Option<Token![in]>,
53        //     pub path: Box<Path>,
54        // }
55    }
56}
57
58#[cfg(feature = "parsing")]
59pub(crate) mod parsing {
60    use super::*;
61    use crate::ext::IdentExt as _;
62    use crate::parse::discouraged::Speculative as _;
63    use crate::parse::{Parse, ParseStream, Result};
64
65    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
66    impl Parse for Visibility {
67        fn parse(input: ParseStream) -> Result<Self> {
68            // Recognize an empty None-delimited group, as produced by a $:vis
69            // matcher that matched no tokens.
70            if input.peek(token::Group) {
71                let ahead = input.fork();
72                let group = crate::group::parse_group(&ahead)?;
73                if group.content.is_empty() {
74                    input.advance_to(&ahead);
75                    return Ok(Visibility::Inherited);
76                }
77            }
78
79            if input.peek(Token![pub]) {
80                Self::parse_pub(input)
81            } else {
82                Ok(Visibility::Inherited)
83            }
84        }
85    }
86
87    impl Visibility {
88        fn parse_pub(input: ParseStream) -> Result<Self> {
89            let pub_token = input.parse::<Token![pub]>()?;
90
91            if input.peek(token::Paren) {
92                let ahead = input.fork();
93
94                let content;
95                let paren_token = parenthesized!(content in ahead);
96                if content.peek(Token![crate])
97                    || content.peek(Token![self])
98                    || content.peek(Token![super])
99                {
100                    let path = content.call(Ident::parse_any)?;
101
102                    // Ensure there are no additional tokens within `content`.
103                    // Without explicitly checking, we may misinterpret a tuple
104                    // field as a restricted visibility, causing a parse error.
105                    // e.g. `pub (crate::A, crate::B)` (Issue #720).
106                    if content.is_empty() {
107                        input.advance_to(&ahead);
108                        return Ok(Visibility::Restricted(VisRestricted {
109                            pub_token,
110                            paren_token,
111                            in_token: None,
112                            path: Box::new(Path::from(path)),
113                        }));
114                    }
115                } else if content.peek(Token![in]) {
116                    let in_token: Token![in] = content.parse()?;
117                    let path = content.call(Path::parse_mod_style)?;
118
119                    input.advance_to(&ahead);
120                    return Ok(Visibility::Restricted(VisRestricted {
121                        pub_token,
122                        paren_token,
123                        in_token: Some(in_token),
124                        path: Box::new(path),
125                    }));
126                }
127            }
128
129            Ok(Visibility::Public(pub_token))
130        }
131
132        #[cfg(feature = "full")]
133        pub(crate) fn is_some(&self) -> bool {
134            match self {
135                Visibility::Inherited => false,
136                _ => true,
137            }
138        }
139    }
140}
141
142#[cfg(feature = "printing")]
143mod printing {
144    use super::*;
145    use proc_macro2::TokenStream;
146    use quote::ToTokens;
147
148    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
149    impl ToTokens for Visibility {
150        fn to_tokens(&self, tokens: &mut TokenStream) {
151            match self {
152                Visibility::Public(pub_token) => pub_token.to_tokens(tokens),
153                Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens),
154                Visibility::Inherited => {}
155            }
156        }
157    }
158
159    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
160    impl ToTokens for VisRestricted {
161        fn to_tokens(&self, tokens: &mut TokenStream) {
162            self.pub_token.to_tokens(tokens);
163            self.paren_token.surround(tokens, |tokens| {
164                // TODO: If we have a path which is not "self" or "super" or
165                // "crate", automatically add the "in" token.
166                self.in_token.to_tokens(tokens);
167                self.path.to_tokens(tokens);
168            });
169        }
170    }
171}
172