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