• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 
3 ast_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 
26 ast_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 
38 ast_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")]
59 pub(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 {
parse(input: ParseStream) -> Result<Self>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 {
parse_pub(input: ParseStream) -> Result<Self>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")]
is_some(&self) -> bool133         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")]
143 mod 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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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