From 4f9fe856a25ab29345b90e7725509e9ee38a37be Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:41 +0200 Subject: Adding upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_ast/src/attr/mod.rs | 632 +++++++++++++++++++------------------ 1 file changed, 324 insertions(+), 308 deletions(-) (limited to 'compiler/rustc_ast/src/attr/mod.rs') 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); @@ -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>); - /// 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 { - 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 { - 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 { - 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 { - 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> { + #[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 { - 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> { 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 { - 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 { - 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 { - Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) - } - - pub fn meta_kind(&self) -> Option { - 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 { 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 { match &self.kind { @@ -321,130 +211,102 @@ impl Attribute { } } -pub struct AttrIdGenerator(WorkerLocal>); - -#[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> { + 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(); - - // 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)); - - self.0.set(id + 1); - AttrId::from_u32(id) + fn value_str(&self) -> Option { + match &self.args { + AttrArgs::Eq(_, args) => args.value_str(), + AttrArgs::Delimited(_) | AttrArgs::Empty => None, + } } -} -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, - style: AttrStyle, - span: Span, -) -> Attribute { - Attribute { - kind: AttrKind::Normal(P(NormalAttr { item, tokens })), - id: g.mk_attr_id(), - style, - span, + pub fn meta(&self, span: Span) -> Option { + Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, 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_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 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_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_kind(&self) -> Option { + MetaItemKind::from_attr_args(&self.args) + } } -pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { - items.iter().any(|item| item.has_name(name)) +impl AttrArgsEq { + fn value_str(&self) -> Option { + 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(), + } + } } impl MetaItem { + /// For a single-segment meta item, returns its name; otherwise, returns `None`. + pub fn ident(&self) -> Option { + 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 + } + + pub fn has_name(&self, name: Symbol) -> bool { + self.path == name + } + + pub fn is_word(&self) -> bool { + matches!(self.kind, MetaItemKind::Word) + } + + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + match &self.kind { + MetaItemKind::List(l) => Some(&**l), + _ => None, + } + } + + /// ```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 { + Some(self.name_value_literal()?.span) + } + + pub fn value_str(&self) -> Option { + self.kind.value_str() + } + fn from_tokens(tokens: &mut iter::Peekable) -> Option where I: Iterator, @@ -508,17 +370,14 @@ impl MetaItem { impl MetaItemKind { pub fn value_str(&self) -> Option { 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 { + fn list_from_tokens(tokens: TokenStream) -> Option> { 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>, + ) -> Option { + 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 { 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>, - ) -> Option { - 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 { + 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 { + 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 { + 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(tokens: &mut iter::Peekable) -> Option where I: Iterator, @@ -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, + 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)) +} -- cgit v1.2.3