1 //! Functions dealing with attributes and meta items.
8 pub use StabilityLevel::*;
9 pub use crate::ast::Attribute;
12 use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
13 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
14 use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
15 use crate::mut_visit::visit_clobber;
16 use crate::source_map::{BytePos, Spanned};
17 use crate::parse::lexer::comments::doc_comment_style;
19 use crate::parse::PResult;
20 use crate::parse::token::{self, Token};
22 use crate::sess::ParseSess;
23 use crate::symbol::{sym, Symbol};
25 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
32 use std::ops::DerefMut;
34 pub fn mark_used(attr: &Attribute) {
35 debug!("marking {:?} as used", attr);
36 GLOBALS.with(|globals| {
37 globals.used_attrs.lock().insert(attr.id);
41 pub fn is_used(attr: &Attribute) -> bool {
42 GLOBALS.with(|globals| {
43 globals.used_attrs.lock().contains(attr.id)
47 pub fn mark_known(attr: &Attribute) {
48 debug!("marking {:?} as known", attr);
49 GLOBALS.with(|globals| {
50 globals.known_attrs.lock().insert(attr.id);
54 pub fn is_known(attr: &Attribute) -> bool {
55 GLOBALS.with(|globals| {
56 globals.known_attrs.lock().contains(attr.id)
60 pub fn is_known_lint_tool(m_item: Ident) -> bool {
61 [sym::clippy, sym::rustc].contains(&m_item.name)
65 /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
66 pub fn meta_item(&self) -> Option<&MetaItem> {
68 NestedMetaItem::MetaItem(ref item) => Some(item),
73 /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
74 pub fn literal(&self) -> Option<&Lit> {
76 NestedMetaItem::Literal(ref lit) => Some(lit),
81 /// Returns `true` if this list item is a MetaItem with a name of `name`.
82 pub fn check_name(&self, name: Symbol) -> bool {
83 self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
86 /// For a single-segment meta item, returns its name; otherwise, returns `None`.
87 pub fn ident(&self) -> Option<Ident> {
88 self.meta_item().and_then(|meta_item| meta_item.ident())
90 pub fn name_or_empty(&self) -> Symbol {
91 self.ident().unwrap_or(Ident::invalid()).name
94 /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
95 /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
96 pub fn value_str(&self) -> Option<Symbol> {
97 self.meta_item().and_then(|meta_item| meta_item.value_str())
100 /// Returns a name and single literal value tuple of the `MetaItem`.
101 pub fn name_value_literal(&self) -> Option<(Name, &Lit)> {
102 self.meta_item().and_then(
103 |meta_item| meta_item.meta_item_list().and_then(
105 if meta_item_list.len() == 1 {
106 if let Some(ident) = meta_item.ident() {
107 if let Some(lit) = meta_item_list[0].literal() {
108 return Some((ident.name, lit));
116 /// Gets a list of inner meta items from a list `MetaItem` type.
117 pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
118 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
121 /// Returns `true` if the variant is `MetaItem`.
122 pub fn is_meta_item(&self) -> bool {
123 self.meta_item().is_some()
126 /// Returns `true` if the variant is `Literal`.
127 pub fn is_literal(&self) -> bool {
128 self.literal().is_some()
131 /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
132 pub fn is_word(&self) -> bool {
133 self.meta_item().map_or(false, |meta_item| meta_item.is_word())
136 /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
137 pub fn is_value_str(&self) -> bool {
138 self.value_str().is_some()
141 /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
142 pub fn is_meta_item_list(&self) -> bool {
143 self.meta_item_list().is_some()
148 /// Returns `true` if the attribute's path matches the argument. If it matches, then the
149 /// attribute is marked as used.
151 /// To check the attribute name without marking it used, use the `path` field directly.
152 pub fn check_name(&self, name: Symbol) -> bool {
153 let matches = self.path == name;
160 /// For a single-segment attribute, returns its name; otherwise, returns `None`.
161 pub fn ident(&self) -> Option<Ident> {
162 if self.path.segments.len() == 1 {
163 Some(self.path.segments[0].ident)
168 pub fn name_or_empty(&self) -> Symbol {
169 self.ident().unwrap_or(Ident::invalid()).name
172 pub fn value_str(&self) -> Option<Symbol> {
173 self.meta().and_then(|meta| meta.value_str())
176 pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
178 Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
183 pub fn is_word(&self) -> bool {
184 self.tokens.is_empty()
187 pub fn is_meta_item_list(&self) -> bool {
188 self.meta_item_list().is_some()
191 /// Indicates if the attribute is a `ValueString`.
192 pub fn is_value_str(&self) -> bool {
193 self.value_str().is_some()
198 /// For a single-segment meta item, returns its name; otherwise, returns `None`.
199 pub fn ident(&self) -> Option<Ident> {
200 if self.path.segments.len() == 1 {
201 Some(self.path.segments[0].ident)
206 pub fn name_or_empty(&self) -> Symbol {
207 self.ident().unwrap_or(Ident::invalid()).name
211 // #[attribute(name = "value")]
213 pub fn name_value_literal(&self) -> Option<&Lit> {
215 MetaItemKind::NameValue(v) => Some(v),
220 pub fn value_str(&self) -> Option<Symbol> {
222 MetaItemKind::NameValue(ref v) => {
224 LitKind::Str(ref s, _) => Some(*s),
232 pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
234 MetaItemKind::List(ref l) => Some(&l[..]),
239 pub fn is_word(&self) -> bool {
241 MetaItemKind::Word => true,
246 pub fn check_name(&self, name: Symbol) -> bool {
250 pub fn is_value_str(&self) -> bool {
251 self.value_str().is_some()
254 pub fn is_meta_item_list(&self) -> bool {
255 self.meta_item_list().is_some()
260 crate fn meta(&self, span: Span) -> Option<MetaItem> {
261 let mut tokens = self.tokens.trees().peekable();
263 path: self.path.clone(),
264 kind: if let Some(kind) = MetaItemKind::from_tokens(&mut tokens) {
265 if tokens.peek().is_some() {
278 /// Extracts the MetaItem from inside this Attribute.
279 pub fn meta(&self) -> Option<MetaItem> {
280 self.item.meta(self.span)
283 pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
285 path: self.path.clone(),
286 kind: parse::parse_in_attr(sess, self, |p| p.parse_meta_item_kind())?,
294 pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
295 let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
296 mk_name_value_item(ident, lit_kind, str_span)
299 pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
300 let lit = Lit::from_lit_kind(lit_kind, lit_span);
301 let span = ident.span.to(lit_span);
302 MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
305 pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
306 MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
309 pub fn mk_word_item(ident: Ident) -> MetaItem {
310 MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
313 pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
314 NestedMetaItem::MetaItem(mk_word_item(ident))
317 crate fn mk_attr_id() -> AttrId {
318 use std::sync::atomic::AtomicUsize;
319 use std::sync::atomic::Ordering;
321 static NEXT_ATTR_ID: AtomicUsize = AtomicUsize::new(0);
323 let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
324 assert!(id != ::std::usize::MAX);
328 pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
330 item: AttrItem { path, tokens },
333 is_sugared_doc: false,
338 /// Returns an inner attribute with the given value and span.
339 pub fn mk_attr_inner(item: MetaItem) -> Attribute {
340 mk_attr(AttrStyle::Inner, item.path, item.kind.tokens(item.span), item.span)
343 /// Returns an outer attribute with the given value and span.
344 pub fn mk_attr_outer(item: MetaItem) -> Attribute {
345 mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span)
348 pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute {
349 let style = doc_comment_style(&text.as_str());
350 let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
351 let lit = Lit::from_lit_kind(lit_kind, span);
354 path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
355 tokens: MetaItemKind::NameValue(lit).tokens(span),
359 is_sugared_doc: true,
364 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
365 items.iter().any(|item| {
366 item.check_name(name)
370 pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
371 attrs.iter().any(|item| {
372 item.check_name(name)
376 pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
377 attrs.iter().find(|attr| attr.check_name(name))
380 pub fn allow_internal_unstable<'a>(
382 span_diagnostic: &'a errors::Handler,
383 ) -> Option<impl Iterator<Item = Symbol> + 'a> {
384 find_by_name(attrs, sym::allow_internal_unstable).and_then(|attr| {
385 attr.meta_item_list().or_else(|| {
386 span_diagnostic.span_err(
388 "allow_internal_unstable expects list of feature names"
391 }).map(|features| features.into_iter().filter_map(move |it| {
392 let name = it.ident().map(|ident| ident.name);
394 span_diagnostic.span_err(
396 "`allow_internal_unstable` expects feature names",
404 pub fn filter_by_name(attrs: &[Attribute], name: Symbol)
405 -> impl Iterator<Item=&Attribute> {
406 attrs.iter().filter(move |attr| attr.check_name(name))
409 pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
411 .find(|at| at.check_name(name))
412 .and_then(|at| at.value_str())
416 fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
417 let mut idents = vec![];
418 let mut last_pos = BytePos(0 as u32);
419 for (i, segment) in self.path.segments.iter().enumerate() {
420 let is_first = i == 0;
422 let mod_sep_span = Span::new(last_pos,
423 segment.ident.span.lo(),
424 segment.ident.span.ctxt());
425 idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
427 idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
428 last_pos = segment.ident.span.hi();
430 idents.extend(self.kind.token_trees_and_joints(self.span));
434 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
435 where I: Iterator<Item = TokenTree>,
437 // FIXME: Share code with `parse_path`.
438 let path = match tokens.next() {
439 Some(TokenTree::Token(Token { kind: kind @ token::Ident(..), span })) |
440 Some(TokenTree::Token(Token { kind: kind @ token::ModSep, span })) => 'arm: {
441 let mut segments = if let token::Ident(name, _) = kind {
442 if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }))
445 vec![PathSegment::from_ident(Ident::new(name, span))]
447 break 'arm Path::from_ident(Ident::new(name, span));
450 vec![PathSegment::path_root(span)]
453 if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span }))
455 segments.push(PathSegment::from_ident(Ident::new(name, span)));
459 if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }))
466 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
467 Path { span, segments }
469 Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
470 token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
471 token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
472 token::Nonterminal::NtPath(ref path) => path.clone(),
477 let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
478 let kind = MetaItemKind::from_tokens(tokens)?;
479 let hi = match kind {
480 MetaItemKind::NameValue(ref lit) => lit.span.hi(),
481 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
484 let span = path.span.with_hi(hi);
485 Some(MetaItem { path, kind, span })
490 pub fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> {
492 MetaItemKind::Word => vec![],
493 MetaItemKind::NameValue(ref lit) => {
495 TokenTree::token(token::Eq, span).into(),
496 lit.token_tree().into(),
499 MetaItemKind::List(ref list) => {
500 let mut tokens = Vec::new();
501 for (i, item) in list.iter().enumerate() {
503 tokens.push(TokenTree::token(token::Comma, span).into());
505 tokens.extend(item.token_trees_and_joints())
508 TokenTree::Delimited(
509 DelimSpan::from_single(span),
511 TokenStream::new(tokens).into(),
518 // Premature conversions of `TokenTree`s to `TokenStream`s can hurt
519 // performance. Do not use this function if `token_trees_and_joints()` can
521 pub fn tokens(&self, span: Span) -> TokenStream {
522 TokenStream::new(self.token_trees_and_joints(span))
525 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind>
526 where I: Iterator<Item = TokenTree>,
528 let delimited = match tokens.peek().cloned() {
529 Some(TokenTree::Token(token)) if token == token::Eq => {
531 return if let Some(TokenTree::Token(token)) = tokens.next() {
532 Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
537 Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => {
541 _ => return Some(MetaItemKind::Word),
544 let mut tokens = delimited.into_trees().peekable();
545 let mut result = Vec::new();
546 while let Some(..) = tokens.peek() {
547 let item = NestedMetaItem::from_tokens(&mut tokens)?;
549 match tokens.next() {
550 None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {}
554 Some(MetaItemKind::List(result))
558 impl NestedMetaItem {
559 pub fn span(&self) -> Span {
561 NestedMetaItem::MetaItem(ref item) => item.span,
562 NestedMetaItem::Literal(ref lit) => lit.span,
566 fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
568 NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(),
569 NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()],
573 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
574 where I: Iterator<Item = TokenTree>,
576 if let Some(TokenTree::Token(token)) = tokens.peek() {
577 if let Ok(lit) = Lit::from_token(token) {
579 return Some(NestedMetaItem::Literal(lit));
583 MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
587 pub trait HasAttrs: Sized {
588 fn attrs(&self) -> &[ast::Attribute];
589 fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
592 impl<T: HasAttrs> HasAttrs for Spanned<T> {
593 fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
594 fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
595 self.node.visit_attrs(f);
599 impl HasAttrs for Vec<Attribute> {
600 fn attrs(&self) -> &[Attribute] {
603 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
608 impl HasAttrs for ThinVec<Attribute> {
609 fn attrs(&self) -> &[Attribute] {
612 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
613 visit_clobber(self, |this| {
614 let mut vec = this.into();
621 impl<T: HasAttrs + 'static> HasAttrs for P<T> {
622 fn attrs(&self) -> &[Attribute] {
625 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
626 (**self).visit_attrs(f);
630 impl HasAttrs for StmtKind {
631 fn attrs(&self) -> &[Attribute] {
633 StmtKind::Local(ref local) => local.attrs(),
634 StmtKind::Item(..) => &[],
635 StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
636 StmtKind::Mac(ref mac) => {
637 let (_, _, ref attrs) = **mac;
643 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
645 StmtKind::Local(local) => local.visit_attrs(f),
646 StmtKind::Item(..) => {}
647 StmtKind::Expr(expr) => expr.visit_attrs(f),
648 StmtKind::Semi(expr) => expr.visit_attrs(f),
649 StmtKind::Mac(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<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
663 self.kind.visit_attrs(f);
667 impl HasAttrs for GenericParam {
668 fn attrs(&self) -> &[ast::Attribute] {
672 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
673 self.attrs.visit_attrs(f);
677 macro_rules! derive_has_attrs {
678 ($($ty:path),*) => { $(
679 impl HasAttrs for $ty {
680 fn attrs(&self) -> &[Attribute] {
684 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
685 self.attrs.visit_attrs(f);
692 Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
693 ast::Field, ast::FieldPat, ast::Variant, ast::Param