1 //! Functions dealing with attributes and meta items.
4 use crate::ast
::{AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}
;
5 use crate::ast
::{Expr, GenericParam, Item, Lit, LitKind, Local, Stmt, StmtKind}
;
6 use crate::ast
::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}
;
7 use crate::ast
::{Path, PathSegment}
;
8 use crate::mut_visit
::visit_clobber
;
10 use crate::token
::{self, CommentKind, Token}
;
11 use crate::tokenstream
::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}
;
13 use rustc_index
::bit_set
::GrowableBitSet
;
14 use rustc_span
::source_map
::{BytePos, Spanned}
;
15 use rustc_span
::symbol
::{sym, Ident, Symbol}
;
19 use std
::ops
::DerefMut
;
21 pub struct MarkedAttrs(GrowableBitSet
<AttrId
>);
24 // We have no idea how many attributes there will be, so just
25 // initiate the vectors with 0 bits. We'll grow them as necessary.
26 pub fn new() -> Self {
27 MarkedAttrs(GrowableBitSet
::new_empty())
30 pub fn mark(&mut self, attr
: &Attribute
) {
31 self.0.insert
(attr
.id
);
34 pub fn is_marked(&self, attr
: &Attribute
) -> bool
{
35 self.0.contains(attr
.id
)
39 pub fn is_known_lint_tool(m_item
: Ident
) -> bool
{
40 [sym
::clippy
, sym
::rustc
].contains(&m_item
.name
)
44 /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
45 pub fn meta_item(&self) -> Option
<&MetaItem
> {
47 NestedMetaItem
::MetaItem(ref item
) => Some(item
),
52 /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
53 pub fn literal(&self) -> Option
<&Lit
> {
55 NestedMetaItem
::Literal(ref lit
) => Some(lit
),
60 /// Returns `true` if this list item is a MetaItem with a name of `name`.
61 pub fn has_name(&self, name
: Symbol
) -> bool
{
62 self.meta_item().map_or(false, |meta_item
| meta_item
.has_name(name
))
65 /// For a single-segment meta item, returns its name; otherwise, returns `None`.
66 pub fn ident(&self) -> Option
<Ident
> {
67 self.meta_item().and_then(|meta_item
| meta_item
.ident())
69 pub fn name_or_empty(&self) -> Symbol
{
70 self.ident().unwrap_or(Ident
::invalid()).name
73 /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
74 /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
75 pub fn value_str(&self) -> Option
<Symbol
> {
76 self.meta_item().and_then(|meta_item
| meta_item
.value_str())
79 /// Returns a name and single literal value tuple of the `MetaItem`.
80 pub fn name_value_literal(&self) -> Option
<(Symbol
, &Lit
)> {
81 self.meta_item().and_then(|meta_item
| {
82 meta_item
.meta_item_list().and_then(|meta_item_list
| {
83 if meta_item_list
.len() == 1 {
84 if let Some(ident
) = meta_item
.ident() {
85 if let Some(lit
) = meta_item_list
[0].literal() {
86 return Some((ident
.name
, lit
));
95 /// Gets a list of inner meta items from a list `MetaItem` type.
96 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
97 self.meta_item().and_then(|meta_item
| meta_item
.meta_item_list())
100 /// Returns `true` if the variant is `MetaItem`.
101 pub fn is_meta_item(&self) -> bool
{
102 self.meta_item().is_some()
105 /// Returns `true` if the variant is `Literal`.
106 pub fn is_literal(&self) -> bool
{
107 self.literal().is_some()
110 /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
111 pub fn is_word(&self) -> bool
{
112 self.meta_item().map_or(false, |meta_item
| meta_item
.is_word())
115 /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
116 pub fn is_value_str(&self) -> bool
{
117 self.value_str().is_some()
120 /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
121 pub fn is_meta_item_list(&self) -> bool
{
122 self.meta_item_list().is_some()
127 pub fn has_name(&self, name
: Symbol
) -> bool
{
129 AttrKind
::Normal(ref item
) => item
.path
== name
,
130 AttrKind
::DocComment(..) => false,
134 /// For a single-segment attribute, returns its name; otherwise, returns `None`.
135 pub fn ident(&self) -> Option
<Ident
> {
137 AttrKind
::Normal(ref item
) => {
138 if item
.path
.segments
.len() == 1 {
139 Some(item
.path
.segments
[0].ident
)
144 AttrKind
::DocComment(..) => None
,
147 pub fn name_or_empty(&self) -> Symbol
{
148 self.ident().unwrap_or(Ident
::invalid()).name
151 pub fn value_str(&self) -> Option
<Symbol
> {
153 AttrKind
::Normal(ref item
) => item
.meta(self.span
).and_then(|meta
| meta
.value_str()),
154 AttrKind
::DocComment(..) => None
,
158 pub fn meta_item_list(&self) -> Option
<Vec
<NestedMetaItem
>> {
160 AttrKind
::Normal(ref item
) => match item
.meta(self.span
) {
161 Some(MetaItem { kind: MetaItemKind::List(list), .. }
) => Some(list
),
164 AttrKind
::DocComment(..) => None
,
168 pub fn is_word(&self) -> bool
{
169 if let AttrKind
::Normal(item
) = &self.kind
{
170 matches
!(item
.args
, MacArgs
::Empty
)
176 pub fn is_meta_item_list(&self) -> bool
{
177 self.meta_item_list().is_some()
180 /// Indicates if the attribute is a `ValueString`.
181 pub fn is_value_str(&self) -> bool
{
182 self.value_str().is_some()
187 /// For a single-segment meta item, returns its name; otherwise, returns `None`.
188 pub fn ident(&self) -> Option
<Ident
> {
189 if self.path
.segments
.len() == 1 { Some(self.path.segments[0].ident) }
else { None }
191 pub fn name_or_empty(&self) -> Symbol
{
192 self.ident().unwrap_or(Ident
::invalid()).name
196 // #[attribute(name = "value")]
198 pub fn name_value_literal(&self) -> Option
<&Lit
> {
200 MetaItemKind
::NameValue(v
) => Some(v
),
205 pub fn value_str(&self) -> Option
<Symbol
> {
207 MetaItemKind
::NameValue(ref v
) => match v
.kind
{
208 LitKind
::Str(ref s
, _
) => Some(*s
),
215 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
217 MetaItemKind
::List(ref l
) => Some(&l
[..]),
222 pub fn is_word(&self) -> bool
{
224 MetaItemKind
::Word
=> true,
229 pub fn has_name(&self, name
: Symbol
) -> bool
{
233 pub fn is_value_str(&self) -> bool
{
234 self.value_str().is_some()
237 pub fn is_meta_item_list(&self) -> bool
{
238 self.meta_item_list().is_some()
243 pub fn span(&self) -> Span
{
244 self.args
.span().map_or(self.path
.span
, |args_span
| self.path
.span
.to(args_span
))
247 pub fn meta(&self, span
: Span
) -> Option
<MetaItem
> {
249 path
: self.path
.clone(),
250 kind
: MetaItemKind
::from_mac_args(&self.args
)?
,
257 pub fn is_doc_comment(&self) -> bool
{
259 AttrKind
::Normal(_
) => false,
260 AttrKind
::DocComment(..) => true,
264 pub fn doc_str(&self) -> Option
<Symbol
> {
266 AttrKind
::DocComment(.., data
) => Some(data
),
267 AttrKind
::Normal(ref item
) if item
.path
== sym
::doc
=> {
268 item
.meta(self.span
).and_then(|meta
| meta
.value_str())
274 pub fn get_normal_item(&self) -> &AttrItem
{
276 AttrKind
::Normal(ref item
) => item
,
277 AttrKind
::DocComment(..) => panic
!("unexpected doc comment"),
281 pub fn unwrap_normal_item(self) -> AttrItem
{
283 AttrKind
::Normal(item
) => item
,
284 AttrKind
::DocComment(..) => panic
!("unexpected doc comment"),
288 /// Extracts the MetaItem from inside this Attribute.
289 pub fn meta(&self) -> Option
<MetaItem
> {
291 AttrKind
::Normal(ref item
) => item
.meta(self.span
),
292 AttrKind
::DocComment(..) => None
,
299 pub fn mk_name_value_item_str(ident
: Ident
, str: Symbol
, str_span
: Span
) -> MetaItem
{
300 let lit_kind
= LitKind
::Str(str, ast
::StrStyle
::Cooked
);
301 mk_name_value_item(ident
, lit_kind
, str_span
)
304 pub fn mk_name_value_item(ident
: Ident
, lit_kind
: LitKind
, lit_span
: Span
) -> MetaItem
{
305 let lit
= Lit
::from_lit_kind(lit_kind
, lit_span
);
306 let span
= ident
.span
.to(lit_span
);
307 MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
310 pub fn mk_list_item(ident
: Ident
, items
: Vec
<NestedMetaItem
>) -> MetaItem
{
311 MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
314 pub fn mk_word_item(ident
: Ident
) -> MetaItem
{
315 MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
318 pub fn mk_nested_word_item(ident
: Ident
) -> NestedMetaItem
{
319 NestedMetaItem
::MetaItem(mk_word_item(ident
))
322 crate fn mk_attr_id() -> AttrId
{
323 use std
::sync
::atomic
::AtomicU32
;
324 use std
::sync
::atomic
::Ordering
;
326 static NEXT_ATTR_ID
: AtomicU32
= AtomicU32
::new(0);
328 let id
= NEXT_ATTR_ID
.fetch_add(1, Ordering
::SeqCst
);
329 assert
!(id
!= u32::MAX
);
333 pub fn mk_attr(style
: AttrStyle
, path
: Path
, args
: MacArgs
, span
: Span
) -> Attribute
{
334 mk_attr_from_item(style
, AttrItem { path, args }
, span
)
337 pub fn mk_attr_from_item(style
: AttrStyle
, item
: AttrItem
, span
: Span
) -> Attribute
{
338 Attribute { kind: AttrKind::Normal(item), id: mk_attr_id(), style, span }
341 /// Returns an inner attribute with the given value and span.
342 pub fn mk_attr_inner(item
: MetaItem
) -> Attribute
{
343 mk_attr(AttrStyle
::Inner
, item
.path
, item
.kind
.mac_args(item
.span
), item
.span
)
346 /// Returns an outer attribute with the given value and span.
347 pub fn mk_attr_outer(item
: MetaItem
) -> Attribute
{
348 mk_attr(AttrStyle
::Outer
, item
.path
, item
.kind
.mac_args(item
.span
), item
.span
)
351 pub fn mk_doc_comment(
352 comment_kind
: CommentKind
,
357 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
360 pub fn list_contains_name(items
: &[NestedMetaItem
], name
: Symbol
) -> bool
{
361 items
.iter().any(|item
| item
.has_name(name
))
365 fn token_trees_and_joints(&self) -> Vec
<TreeAndJoint
> {
366 let mut idents
= vec
![];
367 let mut last_pos
= BytePos(0 as u32);
368 for (i
, segment
) in self.path
.segments
.iter().enumerate() {
369 let is_first
= i
== 0;
372 Span
::new(last_pos
, segment
.ident
.span
.lo(), segment
.ident
.span
.ctxt());
373 idents
.push(TokenTree
::token(token
::ModSep
, mod_sep_span
).into());
375 idents
.push(TokenTree
::Token(Token
::from_ast_ident(segment
.ident
)).into());
376 last_pos
= segment
.ident
.span
.hi();
378 idents
.extend(self.kind
.token_trees_and_joints(self.span
));
382 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItem
>
384 I
: Iterator
<Item
= TokenTree
>,
386 // FIXME: Share code with `parse_path`.
387 let path
= match tokens
.next().map(TokenTree
::uninterpolate
) {
388 Some(TokenTree
::Token(Token
{
389 kind
: kind @
(token
::Ident(..) | token
::ModSep
),
392 let mut segments
= if let token
::Ident(name
, _
) = kind
{
393 if let Some(TokenTree
::Token(Token { kind: token::ModSep, .. }
)) = tokens
.peek()
396 vec
![PathSegment
::from_ident(Ident
::new(name
, span
))]
398 break 'arm Path
::from_ident(Ident
::new(name
, span
));
401 vec
![PathSegment
::path_root(span
)]
404 if let Some(TokenTree
::Token(Token { kind: token::Ident(name, _), span }
)) =
405 tokens
.next().map(TokenTree
::uninterpolate
)
407 segments
.push(PathSegment
::from_ident(Ident
::new(name
, span
)));
411 if let Some(TokenTree
::Token(Token { kind: token::ModSep, .. }
)) = tokens
.peek()
418 let span
= span
.with_hi(segments
.last().unwrap().ident
.span
.hi());
419 Path { span, segments }
421 Some(TokenTree
::Token(Token { kind: token::Interpolated(nt), .. }
)) => match *nt
{
422 token
::Nonterminal
::NtMeta(ref item
) => return item
.meta(item
.path
.span
),
423 token
::Nonterminal
::NtPath(ref path
) => path
.clone(),
428 let list_closing_paren_pos
= tokens
.peek().map(|tt
| tt
.span().hi());
429 let kind
= MetaItemKind
::from_tokens(tokens
)?
;
430 let hi
= match kind
{
431 MetaItemKind
::NameValue(ref lit
) => lit
.span
.hi(),
432 MetaItemKind
::List(..) => list_closing_paren_pos
.unwrap_or(path
.span
.hi()),
435 let span
= path
.span
.with_hi(hi
);
436 Some(MetaItem { path, kind, span }
)
441 pub fn mac_args(&self, span
: Span
) -> MacArgs
{
443 MetaItemKind
::Word
=> MacArgs
::Empty
,
444 MetaItemKind
::NameValue(lit
) => MacArgs
::Eq(span
, lit
.token_tree().into()),
445 MetaItemKind
::List(list
) => {
446 let mut tts
= Vec
::new();
447 for (i
, item
) in list
.iter().enumerate() {
449 tts
.push(TokenTree
::token(token
::Comma
, span
).into());
451 tts
.extend(item
.token_trees_and_joints())
454 DelimSpan
::from_single(span
),
455 MacDelimiter
::Parenthesis
,
456 TokenStream
::new(tts
),
462 fn token_trees_and_joints(&self, span
: Span
) -> Vec
<TreeAndJoint
> {
464 MetaItemKind
::Word
=> vec
![],
465 MetaItemKind
::NameValue(ref lit
) => {
466 vec
![TokenTree
::token(token
::Eq
, span
).into(), lit
.token_tree().into()]
468 MetaItemKind
::List(ref list
) => {
469 let mut tokens
= Vec
::new();
470 for (i
, item
) in list
.iter().enumerate() {
472 tokens
.push(TokenTree
::token(token
::Comma
, span
).into());
474 tokens
.extend(item
.token_trees_and_joints())
477 TokenTree
::Delimited(
478 DelimSpan
::from_single(span
),
480 TokenStream
::new(tokens
),
488 fn list_from_tokens(tokens
: TokenStream
) -> Option
<MetaItemKind
> {
489 let mut tokens
= tokens
.into_trees().peekable();
490 let mut result
= Vec
::new();
491 while let Some(..) = tokens
.peek() {
492 let item
= NestedMetaItem
::from_tokens(&mut tokens
)?
;
494 match tokens
.next() {
495 None
| Some(TokenTree
::Token(Token { kind: token::Comma, .. }
)) => {}
499 Some(MetaItemKind
::List(result
))
502 fn name_value_from_tokens(
503 tokens
: &mut impl Iterator
<Item
= TokenTree
>,
504 ) -> Option
<MetaItemKind
> {
505 match tokens
.next() {
506 Some(TokenTree
::Delimited(_
, token
::NoDelim
, inner_tokens
)) => {
507 MetaItemKind
::name_value_from_tokens(&mut inner_tokens
.trees())
509 Some(TokenTree
::Token(token
)) => {
510 Lit
::from_token(&token
).ok().map(MetaItemKind
::NameValue
)
516 fn from_mac_args(args
: &MacArgs
) -> Option
<MetaItemKind
> {
518 MacArgs
::Delimited(_
, MacDelimiter
::Parenthesis
, tokens
) => {
519 MetaItemKind
::list_from_tokens(tokens
.clone())
521 MacArgs
::Delimited(..) => None
,
522 MacArgs
::Eq(_
, tokens
) => {
523 assert
!(tokens
.len() == 1);
524 MetaItemKind
::name_value_from_tokens(&mut tokens
.trees())
526 MacArgs
::Empty
=> Some(MetaItemKind
::Word
),
531 tokens
: &mut iter
::Peekable
<impl Iterator
<Item
= TokenTree
>>,
532 ) -> Option
<MetaItemKind
> {
533 match tokens
.peek() {
534 Some(TokenTree
::Delimited(_
, token
::Paren
, inner_tokens
)) => {
535 let inner_tokens
= inner_tokens
.clone();
537 MetaItemKind
::list_from_tokens(inner_tokens
)
539 Some(TokenTree
::Delimited(..)) => None
,
540 Some(TokenTree
::Token(Token { kind: token::Eq, .. }
)) => {
542 MetaItemKind
::name_value_from_tokens(tokens
)
544 _
=> Some(MetaItemKind
::Word
),
549 impl NestedMetaItem
{
550 pub fn span(&self) -> Span
{
552 NestedMetaItem
::MetaItem(ref item
) => item
.span
,
553 NestedMetaItem
::Literal(ref lit
) => lit
.span
,
557 fn token_trees_and_joints(&self) -> Vec
<TreeAndJoint
> {
559 NestedMetaItem
::MetaItem(ref item
) => item
.token_trees_and_joints(),
560 NestedMetaItem
::Literal(ref lit
) => vec
![lit
.token_tree().into()],
564 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<NestedMetaItem
>
566 I
: Iterator
<Item
= TokenTree
>,
568 match tokens
.peek() {
569 Some(TokenTree
::Token(token
)) => {
570 if let Ok(lit
) = Lit
::from_token(token
) {
572 return Some(NestedMetaItem
::Literal(lit
));
575 Some(TokenTree
::Delimited(_
, token
::NoDelim
, inner_tokens
)) => {
576 let inner_tokens
= inner_tokens
.clone();
578 return NestedMetaItem
::from_tokens(&mut inner_tokens
.into_trees().peekable());
582 MetaItem
::from_tokens(tokens
).map(NestedMetaItem
::MetaItem
)
586 pub trait HasAttrs
: Sized
{
587 fn attrs(&self) -> &[Attribute
];
588 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>));
591 impl<T
: HasAttrs
> HasAttrs
for Spanned
<T
> {
592 fn attrs(&self) -> &[Attribute
] {
595 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
596 self.node
.visit_attrs(f
);
600 impl HasAttrs
for Vec
<Attribute
> {
601 fn attrs(&self) -> &[Attribute
] {
604 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
609 impl HasAttrs
for AttrVec
{
610 fn attrs(&self) -> &[Attribute
] {
613 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
614 visit_clobber(self, |this
| {
615 let mut vec
= this
.into();
622 impl<T
: HasAttrs
+ '
static> HasAttrs
for P
<T
> {
623 fn attrs(&self) -> &[Attribute
] {
626 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
627 (**self).visit_attrs(f
);
631 impl HasAttrs
for StmtKind
{
632 fn attrs(&self) -> &[Attribute
] {
634 StmtKind
::Local(ref local
) => local
.attrs(),
635 StmtKind
::Expr(ref expr
) | StmtKind
::Semi(ref expr
) => expr
.attrs(),
636 StmtKind
::Empty
| StmtKind
::Item(..) => &[],
637 StmtKind
::MacCall(ref mac
) => {
638 let (_
, _
, ref attrs
) = **mac
;
644 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
646 StmtKind
::Local(local
) => local
.visit_attrs(f
),
647 StmtKind
::Expr(expr
) | StmtKind
::Semi(expr
) => expr
.visit_attrs(f
),
648 StmtKind
::Empty
| StmtKind
::Item(..) => {}
649 StmtKind
::MacCall(mac
) => {
650 let (_mac
, _style
, attrs
) = mac
.deref_mut();
651 attrs
.visit_attrs(f
);
657 impl HasAttrs
for Stmt
{
658 fn attrs(&self) -> &[ast
::Attribute
] {
662 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
663 self.kind
.visit_attrs(f
);
667 macro_rules
! derive_has_attrs
{
668 ($
($ty
:path
),*) => { $
(
669 impl HasAttrs
for $ty
{
670 fn attrs(&self) -> &[Attribute
] {
674 fn visit_attrs(&mut self, f
: impl FnOnce(&mut Vec
<Attribute
>)) {
675 self.attrs
.visit_attrs(f
);
682 Item
, Expr
, Local
, ast
::AssocItem
, ast
::ForeignItem
, ast
::StructField
, ast
::Arm
,
683 ast
::Field
, ast
::FieldPat
, ast
::Variant
, ast
::Param
, GenericParam