rustc_ast: Merge impls and reorder methods for attributes and meta items

This commit is contained in:
Vadim Petrochenkov 2023-02-11 22:51:21 +04:00
parent 8dabf5da9e
commit 37a72a2e3e

View File

@ -40,310 +40,6 @@ 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,
}
}
/// 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 `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))
}
/// 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
}
/// 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 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
})
})
}
/// 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 `true` if the variant is `MetaItem`.
pub fn is_meta_item(&self) -> bool {
self.meta_item().is_some()
}
/// 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())
}
/// See [`MetaItem::name_value_literal_span`].
pub fn name_value_literal_span(&self) -> Option<Span> {
self.meta_item()?.name_value_literal_span()
}
}
impl Attribute {
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
match &self.kind {
AttrKind::Normal(normal) => normal.item.path == name,
AttrKind::DocComment(..) => false,
}
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) => {
if let [ident] = &*normal.item.path.segments {
Some(ident.ident)
} else {
None
}
}
AttrKind::DocComment(..) => None,
}
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
pub fn value_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.value_str(),
AttrKind::DocComment(..) => None,
}
}
pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_item_list(),
AttrKind::DocComment(..) => None,
}
}
pub fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty)
} else {
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> {
match &self.kind {
MetaItemKind::NameValue(v) => Some(v),
_ => 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 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(),
}
}
}
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)
}
fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.args {
AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
}
}
fn value_str(&self) -> Option<Symbol> {
match &self.args {
AttrArgs::Eq(_, args) => args.value_str(),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
}
}
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,
}
}
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
/// * `#[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(normal) if normal.item.path == sym::doc => {
normal.item.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
/// * `#[doc = "doc"]` returns `Some("doc")`.
/// * `#[doc(...)]` returns `None`.
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.value_str(),
_ => None,
}
}
pub fn may_have_doc_links(&self) -> bool {
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 {
AttrKind::Normal(normal) => normal.item.meta(self.span),
AttrKind::DocComment(..) => None,
}
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_kind(),
AttrKind::DocComment(..) => None,
}
}
pub fn tokens(&self) -> TokenStream {
match &self.kind {
AttrKind::Normal(normal) => normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_tokenstream(),
&AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
Token::new(token::DocComment(comment_kind, self.style, data), self.span),
Spacing::Alone,
)]),
}
}
}
pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
#[cfg(debug_assertions)]
@ -381,93 +77,236 @@ impl AttrIdGenerator {
}
}
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 Attribute {
pub fn get_normal_item(&self) -> &AttrItem {
match &self.kind {
AttrKind::Normal(normal) => &normal.item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
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 unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => normal.into_inner().item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
/// 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,
}
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) => {
if let [ident] = &*normal.item.path.segments {
Some(ident.ident)
} else {
None
}
}
AttrKind::DocComment(..) => None,
}
}
pub fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
match &self.kind {
AttrKind::Normal(normal) => normal.item.path == name,
AttrKind::DocComment(..) => false,
}
}
pub fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty)
} else {
false
}
}
pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_item_list(),
AttrKind::DocComment(..) => None,
}
}
pub fn value_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.value_str(),
AttrKind::DocComment(..) => None,
}
}
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
/// * `#[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(normal) if normal.item.path == sym::doc => {
normal.item.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
/// * `#[doc = "doc"]` returns `Some("doc")`.
/// * `#[doc(...)]` returns `None`.
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.value_str(),
_ => None,
}
}
pub fn may_have_doc_links(&self) -> bool {
self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
}
/// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta(self.span),
AttrKind::DocComment(..) => None,
}
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_kind(),
AttrKind::DocComment(..) => None,
}
}
pub fn tokens(&self) -> TokenStream {
match &self.kind {
AttrKind::Normal(normal) => normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_tokenstream(),
&AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
Token::new(token::DocComment(comment_kind, self.style, data), self.span),
Spacing::Alone,
)]),
}
}
}
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)
impl AttrItem {
pub fn span(&self) -> Span {
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
}
fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
match &self.args {
AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
}
}
fn value_str(&self) -> Option<Symbol> {
match &self.args {
AttrArgs::Eq(_, args) => args.value_str(),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
}
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)
}
}
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 list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
items.iter().any(|item| item.has_name(name))
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(),
}
}
}
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
}
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<Span> {
Some(self.name_value_literal()?.span)
}
pub fn value_str(&self) -> Option<Symbol> {
self.kind.value_str()
}
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
where
I: Iterator<Item = TokenTree>,
@ -564,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),
@ -585,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).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),
}
}
}
impl NestedMetaItem {
@ -613,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>,
@ -634,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))
}