summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast/src/attr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:50 +0000
commit2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35 (patch)
treed325add32978dbdc1db975a438b3a77d571b1ab8 /compiler/rustc_ast/src/attr
parentReleasing progress-linux version 1.68.2+dfsg1-1~progress7.99u1. (diff)
downloadrustc-2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35.tar.xz
rustc-2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35.zip
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_ast/src/attr')
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs622
1 files changed, 319 insertions, 303 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index c6b6207b3..2e83b3e62 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -20,7 +20,7 @@ use std::iter;
use std::ops::BitXor;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicU32, Ordering};
-use thin_vec::thin_vec;
+use thin_vec::{thin_vec, ThinVec};
pub struct MarkedAttrs(GrowableBitSet<AttrId>);
@@ -40,84 +40,65 @@ impl MarkedAttrs {
}
}
-impl NestedMetaItem {
- /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
- pub fn meta_item(&self) -> Option<&MetaItem> {
- match self {
- NestedMetaItem::MetaItem(item) => Some(item),
- _ => None,
- }
- }
+pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
- /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
- pub fn lit(&self) -> Option<&MetaItemLit> {
- match self {
- NestedMetaItem::Lit(lit) => Some(lit),
- _ => None,
- }
- }
+#[cfg(debug_assertions)]
+static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX);
- /// Returns `true` if this list item is a MetaItem with a name of `name`.
- pub fn has_name(&self, name: Symbol) -> bool {
- self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
- }
+impl AttrIdGenerator {
+ pub fn new() -> Self {
+ // We use `(index as u32).reverse_bits()` to initialize the
+ // starting value of AttrId in each worker thread.
+ // The `index` is the index of the worker thread.
+ // This ensures that the AttrId generated in each thread is unique.
+ AttrIdGenerator(WorkerLocal::new(|index| {
+ let index: u32 = index.try_into().unwrap();
- /// For a single-segment meta item, returns its name; otherwise, returns `None`.
- pub fn ident(&self) -> Option<Ident> {
- self.meta_item().and_then(|meta_item| meta_item.ident())
- }
- pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::empty).name
- }
+ #[cfg(debug_assertions)]
+ {
+ let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits();
+ MAX_ATTR_ID.fetch_min(max_id, Ordering::Release);
+ }
- /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
- /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
- pub fn value_str(&self) -> Option<Symbol> {
- self.meta_item().and_then(|meta_item| meta_item.value_str())
+ Cell::new(index.reverse_bits())
+ }))
}
- /// Returns a name and single literal value tuple of the `MetaItem`.
- pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> {
- self.meta_item().and_then(|meta_item| {
- meta_item.meta_item_list().and_then(|meta_item_list| {
- if meta_item_list.len() == 1
- && let Some(ident) = meta_item.ident()
- && let Some(lit) = meta_item_list[0].lit()
- {
- return Some((ident.name, lit));
- }
- None
- })
- })
- }
+ pub fn mk_attr_id(&self) -> AttrId {
+ let id = self.0.get();
- /// Gets a list of inner meta items from a list `MetaItem` type.
- pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
- self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
- }
+ // Ensure the assigned attr_id does not overlap the bits
+ // representing the number of threads.
+ #[cfg(debug_assertions)]
+ assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire));
- /// Returns `true` if the variant is `MetaItem`.
- pub fn is_meta_item(&self) -> bool {
- self.meta_item().is_some()
+ self.0.set(id + 1);
+ AttrId::from_u32(id)
}
+}
- /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
- pub fn is_word(&self) -> bool {
- self.meta_item().map_or(false, |meta_item| meta_item.is_word())
+impl Attribute {
+ pub fn get_normal_item(&self) -> &AttrItem {
+ match &self.kind {
+ AttrKind::Normal(normal) => &normal.item,
+ AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+ }
}
- /// See [`MetaItem::name_value_literal_span`].
- pub fn name_value_literal_span(&self) -> Option<Span> {
- self.meta_item()?.name_value_literal_span()
+ pub fn unwrap_normal_item(self) -> AttrItem {
+ match self.kind {
+ AttrKind::Normal(normal) => normal.into_inner().item,
+ AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+ }
}
-}
-impl Attribute {
- #[inline]
- pub fn has_name(&self, name: Symbol) -> bool {
- match &self.kind {
- AttrKind::Normal(normal) => normal.item.path == name,
- AttrKind::DocComment(..) => false,
+ /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
+ /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
+ /// a doc comment) will return `false`.
+ pub fn is_doc_comment(&self) -> bool {
+ match self.kind {
+ AttrKind::Normal(..) => false,
+ AttrKind::DocComment(..) => true,
}
}
@@ -138,20 +119,11 @@ impl Attribute {
self.ident().unwrap_or_else(Ident::empty).name
}
- pub fn value_str(&self) -> Option<Symbol> {
- match &self.kind {
- AttrKind::Normal(normal) => normal.item.meta_kind().and_then(|kind| kind.value_str()),
- AttrKind::DocComment(..) => None,
- }
- }
-
- pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
+ #[inline]
+ pub fn has_name(&self, name: Symbol) -> bool {
match &self.kind {
- AttrKind::Normal(normal) => match normal.item.meta_kind() {
- Some(MetaItemKind::List(list)) => Some(list),
- _ => None,
- },
- AttrKind::DocComment(..) => None,
+ AttrKind::Normal(normal) => normal.item.path == name,
+ AttrKind::DocComment(..) => false,
}
}
@@ -162,82 +134,18 @@ impl Attribute {
false
}
}
-}
-
-impl MetaItem {
- /// For a single-segment meta item, returns its name; otherwise, returns `None`.
- pub fn ident(&self) -> Option<Ident> {
- if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
- }
- pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::empty).name
- }
- /// ```text
- /// Example:
- /// #[attribute(name = "value")]
- /// ^^^^^^^^^^^^^^
- /// ```
- pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
+ pub fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
match &self.kind {
- MetaItemKind::NameValue(v) => Some(v),
- _ => None,
+ AttrKind::Normal(normal) => normal.item.meta_item_list(),
+ AttrKind::DocComment(..) => None,
}
}
pub fn value_str(&self) -> Option<Symbol> {
- self.kind.value_str()
- }
-
- pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
match &self.kind {
- MetaItemKind::List(l) => Some(&**l),
- _ => None,
- }
- }
-
- pub fn is_word(&self) -> bool {
- matches!(self.kind, MetaItemKind::Word)
- }
-
- pub fn has_name(&self, name: Symbol) -> bool {
- self.path == name
- }
-
- /// This is used in case you want the value span instead of the whole attribute. Example:
- ///
- /// ```text
- /// #[doc(alias = "foo")]
- /// ```
- ///
- /// In here, it'll return a span for `"foo"`.
- pub fn name_value_literal_span(&self) -> Option<Span> {
- Some(self.name_value_literal()?.span)
- }
-}
-
-impl AttrItem {
- pub fn span(&self) -> Span {
- self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
- }
-
- pub fn meta(&self, span: Span) -> Option<MetaItem> {
- Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
- }
-
- pub fn meta_kind(&self) -> Option<MetaItemKind> {
- MetaItemKind::from_attr_args(&self.args)
- }
-}
-
-impl Attribute {
- /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
- /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
- /// a doc comment) will return `false`.
- pub fn is_doc_comment(&self) -> bool {
- match self.kind {
- AttrKind::Normal(..) => false,
- AttrKind::DocComment(..) => true,
+ AttrKind::Normal(normal) => normal.item.value_str(),
+ AttrKind::DocComment(..) => None,
}
}
@@ -247,13 +155,11 @@ impl Attribute {
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
/// * `#[doc(...)]` returns `None`.
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
- match self.kind {
- AttrKind::DocComment(kind, data) => Some((data, kind)),
- AttrKind::Normal(ref normal) if normal.item.path == sym::doc => normal
- .item
- .meta_kind()
- .and_then(|kind| kind.value_str())
- .map(|data| (data, CommentKind::Line)),
+ match &self.kind {
+ AttrKind::DocComment(kind, data) => Some((*data, *kind)),
+ AttrKind::Normal(normal) if normal.item.path == sym::doc => {
+ normal.item.value_str().map(|s| (s, CommentKind::Line))
+ }
_ => None,
}
}
@@ -265,9 +171,7 @@ impl Attribute {
pub fn doc_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::DocComment(.., data) => Some(*data),
- AttrKind::Normal(normal) if normal.item.path == sym::doc => {
- normal.item.meta_kind().and_then(|kind| kind.value_str())
- }
+ AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
_ => None,
}
}
@@ -276,20 +180,6 @@ impl Attribute {
self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
}
- pub fn get_normal_item(&self) -> &AttrItem {
- match &self.kind {
- AttrKind::Normal(normal) => &normal.item,
- AttrKind::DocComment(..) => panic!("unexpected doc comment"),
- }
- }
-
- pub fn unwrap_normal_item(self) -> AttrItem {
- match self.kind {
- AttrKind::Normal(normal) => normal.into_inner().item,
- AttrKind::DocComment(..) => panic!("unexpected doc comment"),
- }
- }
-
/// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> {
match &self.kind {
@@ -321,130 +211,102 @@ impl Attribute {
}
}
-pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
-
-#[cfg(debug_assertions)]
-static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX);
-
-impl AttrIdGenerator {
- pub fn new() -> Self {
- // We use `(index as u32).reverse_bits()` to initialize the
- // starting value of AttrId in each worker thread.
- // The `index` is the index of the worker thread.
- // This ensures that the AttrId generated in each thread is unique.
- AttrIdGenerator(WorkerLocal::new(|index| {
- let index: u32 = index.try_into().unwrap();
+impl AttrItem {
+ pub fn span(&self) -> Span {
+ self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
+ }
- #[cfg(debug_assertions)]
- {
- let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits();
- MAX_ATTR_ID.fetch_min(max_id, Ordering::Release);
+ fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
+ match &self.args {
+ AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
+ MetaItemKind::list_from_tokens(args.tokens.clone())
}
-
- Cell::new(index.reverse_bits())
- }))
+ AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
+ }
}
- pub fn mk_attr_id(&self) -> AttrId {
- let id = self.0.get();
+ fn value_str(&self) -> Option<Symbol> {
+ match &self.args {
+ AttrArgs::Eq(_, args) => args.value_str(),
+ AttrArgs::Delimited(_) | AttrArgs::Empty => None,
+ }
+ }
- // Ensure the assigned attr_id does not overlap the bits
- // representing the number of threads.
- #[cfg(debug_assertions)]
- assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire));
+ pub fn meta(&self, span: Span) -> Option<MetaItem> {
+ Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
+ }
- self.0.set(id + 1);
- AttrId::from_u32(id)
+ pub fn meta_kind(&self) -> Option<MetaItemKind> {
+ MetaItemKind::from_attr_args(&self.args)
}
}
-pub fn mk_attr(
- g: &AttrIdGenerator,
- style: AttrStyle,
- path: Path,
- args: AttrArgs,
- span: Span,
-) -> Attribute {
- mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
+impl AttrArgsEq {
+ fn value_str(&self) -> Option<Symbol> {
+ match self {
+ AttrArgsEq::Ast(expr) => match expr.kind {
+ ExprKind::Lit(token_lit) => {
+ LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
+ }
+ _ => None,
+ },
+ AttrArgsEq::Hir(lit) => lit.kind.str(),
+ }
+ }
}
-pub fn mk_attr_from_item(
- g: &AttrIdGenerator,
- item: AttrItem,
- tokens: Option<LazyAttrTokenStream>,
- style: AttrStyle,
- span: Span,
-) -> Attribute {
- Attribute {
- kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
- id: g.mk_attr_id(),
- style,
- span,
+impl MetaItem {
+ /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+ pub fn ident(&self) -> Option<Ident> {
+ if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
}
-}
-pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
- let path = Path::from_ident(Ident::new(name, span));
- let args = AttrArgs::Empty;
- mk_attr(g, style, path, args, span)
-}
+ pub fn name_or_empty(&self) -> Symbol {
+ self.ident().unwrap_or_else(Ident::empty).name
+ }
-pub fn mk_attr_name_value_str(
- g: &AttrIdGenerator,
- style: AttrStyle,
- name: Symbol,
- val: Symbol,
- span: Span,
-) -> Attribute {
- let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
- let expr = P(Expr {
- id: DUMMY_NODE_ID,
- kind: ExprKind::Lit(lit),
- span,
- attrs: AttrVec::new(),
- tokens: None,
- });
- let path = Path::from_ident(Ident::new(name, span));
- let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
- mk_attr(g, style, path, args, span)
-}
+ pub fn has_name(&self, name: Symbol) -> bool {
+ self.path == name
+ }
-pub fn mk_attr_nested_word(
- g: &AttrIdGenerator,
- style: AttrStyle,
- outer: Symbol,
- inner: Symbol,
- span: Span,
-) -> Attribute {
- let inner_tokens = TokenStream::new(vec![TokenTree::Token(
- Token::from_ast_ident(Ident::new(inner, span)),
- Spacing::Alone,
- )]);
- let outer_ident = Ident::new(outer, span);
- let path = Path::from_ident(outer_ident);
- let attr_args = AttrArgs::Delimited(DelimArgs {
- dspan: DelimSpan::from_single(span),
- delim: MacDelimiter::Parenthesis,
- tokens: inner_tokens,
- });
- mk_attr(g, style, path, attr_args, span)
-}
+ pub fn is_word(&self) -> bool {
+ matches!(self.kind, MetaItemKind::Word)
+ }
-pub fn mk_doc_comment(
- g: &AttrIdGenerator,
- comment_kind: CommentKind,
- style: AttrStyle,
- data: Symbol,
- span: Span,
-) -> Attribute {
- Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
-}
+ pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+ match &self.kind {
+ MetaItemKind::List(l) => Some(&**l),
+ _ => None,
+ }
+ }
-pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
- items.iter().any(|item| item.has_name(name))
-}
+ /// ```text
+ /// Example:
+ /// #[attribute(name = "value")]
+ /// ^^^^^^^^^^^^^^
+ /// ```
+ pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
+ match &self.kind {
+ MetaItemKind::NameValue(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// This is used in case you want the value span instead of the whole attribute. Example:
+ ///
+ /// ```text
+ /// #[doc(alias = "foo")]
+ /// ```
+ ///
+ /// In here, it'll return a span for `"foo"`.
+ pub fn name_value_literal_span(&self) -> Option<Span> {
+ Some(self.name_value_literal()?.span)
+ }
+
+ pub fn value_str(&self) -> Option<Symbol> {
+ self.kind.value_str()
+ }
-impl MetaItem {
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
where
I: Iterator<Item = TokenTree>,
@@ -508,17 +370,14 @@ impl MetaItem {
impl MetaItemKind {
pub fn value_str(&self) -> Option<Symbol> {
match self {
- MetaItemKind::NameValue(v) => match v.kind {
- LitKind::Str(s, _) => Some(s),
- _ => None,
- },
+ MetaItemKind::NameValue(v) => v.kind.str(),
_ => None,
}
}
- fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
+ fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<NestedMetaItem>> {
let mut tokens = tokens.into_trees().peekable();
- let mut result = Vec::new();
+ let mut result = ThinVec::new();
while tokens.peek().is_some() {
let item = NestedMetaItem::from_tokens(&mut tokens)?;
result.push(item);
@@ -527,7 +386,7 @@ impl MetaItemKind {
_ => return None,
}
}
- Some(MetaItemKind::List(result))
+ Some(result)
}
fn name_value_from_tokens(
@@ -544,6 +403,24 @@ impl MetaItemKind {
}
}
+ fn from_tokens(
+ tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
+ ) -> Option<MetaItemKind> {
+ match tokens.peek() {
+ Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
+ let inner_tokens = inner_tokens.clone();
+ tokens.next();
+ MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
+ }
+ Some(TokenTree::Delimited(..)) => None,
+ Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
+ tokens.next();
+ MetaItemKind::name_value_from_tokens(tokens)
+ }
+ _ => Some(MetaItemKind::Word),
+ }
+ }
+
fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
match args {
AttrArgs::Empty => Some(MetaItemKind::Word),
@@ -551,7 +428,7 @@ impl MetaItemKind {
dspan: _,
delim: MacDelimiter::Parenthesis,
tokens,
- }) => MetaItemKind::list_from_tokens(tokens.clone()),
+ }) => MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List),
AttrArgs::Delimited(..) => None,
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
ExprKind::Lit(token_lit) => {
@@ -565,24 +442,6 @@ impl MetaItemKind {
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
}
}
-
- fn from_tokens(
- tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
- ) -> Option<MetaItemKind> {
- match tokens.peek() {
- Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
- let inner_tokens = inner_tokens.clone();
- tokens.next();
- MetaItemKind::list_from_tokens(inner_tokens)
- }
- Some(TokenTree::Delimited(..)) => None,
- Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
- tokens.next();
- MetaItemKind::name_value_from_tokens(tokens)
- }
- _ => Some(MetaItemKind::Word),
- }
- }
}
impl NestedMetaItem {
@@ -593,6 +452,77 @@ impl NestedMetaItem {
}
}
+ /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+ pub fn ident(&self) -> Option<Ident> {
+ self.meta_item().and_then(|meta_item| meta_item.ident())
+ }
+
+ pub fn name_or_empty(&self) -> Symbol {
+ self.ident().unwrap_or_else(Ident::empty).name
+ }
+
+ /// Returns `true` if this list item is a MetaItem with a name of `name`.
+ pub fn has_name(&self, name: Symbol) -> bool {
+ self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
+ }
+
+ /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
+ pub fn is_word(&self) -> bool {
+ self.meta_item().map_or(false, |meta_item| meta_item.is_word())
+ }
+
+ /// Gets a list of inner meta items from a list `MetaItem` type.
+ pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+ self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
+ }
+
+ /// Returns a name and single literal value tuple of the `MetaItem`.
+ pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> {
+ self.meta_item().and_then(|meta_item| {
+ meta_item.meta_item_list().and_then(|meta_item_list| {
+ if meta_item_list.len() == 1
+ && let Some(ident) = meta_item.ident()
+ && let Some(lit) = meta_item_list[0].lit()
+ {
+ return Some((ident.name, lit));
+ }
+ None
+ })
+ })
+ }
+
+ /// See [`MetaItem::name_value_literal_span`].
+ pub fn name_value_literal_span(&self) -> Option<Span> {
+ self.meta_item()?.name_value_literal_span()
+ }
+
+ /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
+ /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
+ pub fn value_str(&self) -> Option<Symbol> {
+ self.meta_item().and_then(|meta_item| meta_item.value_str())
+ }
+
+ /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
+ pub fn lit(&self) -> Option<&MetaItemLit> {
+ match self {
+ NestedMetaItem::Lit(lit) => Some(lit),
+ _ => None,
+ }
+ }
+
+ /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
+ pub fn meta_item(&self) -> Option<&MetaItem> {
+ match self {
+ NestedMetaItem::MetaItem(item) => Some(item),
+ _ => None,
+ }
+ }
+
+ /// Returns `true` if the variant is `MetaItem`.
+ pub fn is_meta_item(&self) -> bool {
+ self.meta_item().is_some()
+ }
+
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
where
I: Iterator<Item = TokenTree>,
@@ -614,3 +544,89 @@ impl NestedMetaItem {
MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
}
}
+
+pub fn mk_doc_comment(
+ g: &AttrIdGenerator,
+ comment_kind: CommentKind,
+ style: AttrStyle,
+ data: Symbol,
+ span: Span,
+) -> Attribute {
+ Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
+}
+
+pub fn mk_attr(
+ g: &AttrIdGenerator,
+ style: AttrStyle,
+ path: Path,
+ args: AttrArgs,
+ span: Span,
+) -> Attribute {
+ mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
+}
+
+pub fn mk_attr_from_item(
+ g: &AttrIdGenerator,
+ item: AttrItem,
+ tokens: Option<LazyAttrTokenStream>,
+ style: AttrStyle,
+ span: Span,
+) -> Attribute {
+ Attribute {
+ kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
+ id: g.mk_attr_id(),
+ style,
+ span,
+ }
+}
+
+pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
+ let path = Path::from_ident(Ident::new(name, span));
+ let args = AttrArgs::Empty;
+ mk_attr(g, style, path, args, span)
+}
+
+pub fn mk_attr_nested_word(
+ g: &AttrIdGenerator,
+ style: AttrStyle,
+ outer: Symbol,
+ inner: Symbol,
+ span: Span,
+) -> Attribute {
+ let inner_tokens = TokenStream::new(vec![TokenTree::Token(
+ Token::from_ast_ident(Ident::new(inner, span)),
+ Spacing::Alone,
+ )]);
+ let outer_ident = Ident::new(outer, span);
+ let path = Path::from_ident(outer_ident);
+ let attr_args = AttrArgs::Delimited(DelimArgs {
+ dspan: DelimSpan::from_single(span),
+ delim: MacDelimiter::Parenthesis,
+ tokens: inner_tokens,
+ });
+ mk_attr(g, style, path, attr_args, span)
+}
+
+pub fn mk_attr_name_value_str(
+ g: &AttrIdGenerator,
+ style: AttrStyle,
+ name: Symbol,
+ val: Symbol,
+ span: Span,
+) -> Attribute {
+ let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
+ let expr = P(Expr {
+ id: DUMMY_NODE_ID,
+ kind: ExprKind::Lit(lit),
+ span,
+ attrs: AttrVec::new(),
+ tokens: None,
+ });
+ let path = Path::from_ident(Ident::new(name, span));
+ let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
+ mk_attr(g, style, path, args, span)
+}
+
+pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
+ items.iter().any(|item| item.has_name(name))
+}