restriction.rs 6.0 KB

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