]> git.lizzy.rs Git - rust.git/blob - src/librustc_ast/attr/mod.rs
Merge branch 'master' into feature/incorporate-tracing
[rust.git] / src / librustc_ast / attr / mod.rs
1 //! Functions dealing with attributes and meta items.
2
3 use crate::ast;
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;
9 use crate::ptr::P;
10 use crate::token::{self, Token};
11 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
12
13 use rustc_data_structures::sync::Lock;
14 use rustc_index::bit_set::GrowableBitSet;
15 use rustc_span::edition::{Edition, DEFAULT_EDITION};
16 use rustc_span::source_map::{BytePos, Spanned};
17 use rustc_span::symbol::{sym, Ident, Symbol};
18 use rustc_span::Span;
19
20 use log::debug;
21 use std::iter;
22 use std::ops::DerefMut;
23
24 // Per-session global variables: this struct is stored in thread-local storage
25 // in such a way that it is accessible without any kind of handle to all
26 // threads within the compilation session, but is not accessible outside the
27 // session.
28 pub struct SessionGlobals {
29     used_attrs: Lock<GrowableBitSet<AttrId>>,
30     known_attrs: Lock<GrowableBitSet<AttrId>>,
31     span_session_globals: rustc_span::SessionGlobals,
32 }
33
34 impl SessionGlobals {
35     fn new(edition: Edition) -> SessionGlobals {
36         SessionGlobals {
37             // We have no idea how many attributes there will be, so just
38             // initiate the vectors with 0 bits. We'll grow them as necessary.
39             used_attrs: Lock::new(GrowableBitSet::new_empty()),
40             known_attrs: Lock::new(GrowableBitSet::new_empty()),
41             span_session_globals: rustc_span::SessionGlobals::new(edition),
42         }
43     }
44 }
45
46 pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
47     let ast_session_globals = SessionGlobals::new(edition);
48     SESSION_GLOBALS.set(&ast_session_globals, || {
49         rustc_span::SESSION_GLOBALS.set(&ast_session_globals.span_session_globals, f)
50     })
51 }
52
53 pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
54     with_session_globals(DEFAULT_EDITION, f)
55 }
56
57 scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
58
59 pub fn mark_used(attr: &Attribute) {
60     debug!("marking {:?} as used", attr);
61     SESSION_GLOBALS.with(|session_globals| {
62         session_globals.used_attrs.lock().insert(attr.id);
63     });
64 }
65
66 pub fn is_used(attr: &Attribute) -> bool {
67     SESSION_GLOBALS.with(|session_globals| session_globals.used_attrs.lock().contains(attr.id))
68 }
69
70 pub fn mark_known(attr: &Attribute) {
71     debug!("marking {:?} as known", attr);
72     SESSION_GLOBALS.with(|session_globals| {
73         session_globals.known_attrs.lock().insert(attr.id);
74     });
75 }
76
77 pub fn is_known(attr: &Attribute) -> bool {
78     SESSION_GLOBALS.with(|session_globals| session_globals.known_attrs.lock().contains(attr.id))
79 }
80
81 pub fn is_known_lint_tool(m_item: Ident) -> bool {
82     [sym::clippy, sym::rustc].contains(&m_item.name)
83 }
84
85 impl NestedMetaItem {
86     /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
87     pub fn meta_item(&self) -> Option<&MetaItem> {
88         match *self {
89             NestedMetaItem::MetaItem(ref item) => Some(item),
90             _ => None,
91         }
92     }
93
94     /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
95     pub fn literal(&self) -> Option<&Lit> {
96         match *self {
97             NestedMetaItem::Literal(ref lit) => Some(lit),
98             _ => None,
99         }
100     }
101
102     /// Returns `true` if this list item is a MetaItem with a name of `name`.
103     pub fn has_name(&self, name: Symbol) -> bool {
104         self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
105     }
106
107     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
108     pub fn ident(&self) -> Option<Ident> {
109         self.meta_item().and_then(|meta_item| meta_item.ident())
110     }
111     pub fn name_or_empty(&self) -> Symbol {
112         self.ident().unwrap_or(Ident::invalid()).name
113     }
114
115     /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
116     /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
117     pub fn value_str(&self) -> Option<Symbol> {
118         self.meta_item().and_then(|meta_item| meta_item.value_str())
119     }
120
121     /// Returns a name and single literal value tuple of the `MetaItem`.
122     pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> {
123         self.meta_item().and_then(|meta_item| {
124             meta_item.meta_item_list().and_then(|meta_item_list| {
125                 if meta_item_list.len() == 1 {
126                     if let Some(ident) = meta_item.ident() {
127                         if let Some(lit) = meta_item_list[0].literal() {
128                             return Some((ident.name, lit));
129                         }
130                     }
131                 }
132                 None
133             })
134         })
135     }
136
137     /// Gets a list of inner meta items from a list `MetaItem` type.
138     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
139         self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
140     }
141
142     /// Returns `true` if the variant is `MetaItem`.
143     pub fn is_meta_item(&self) -> bool {
144         self.meta_item().is_some()
145     }
146
147     /// Returns `true` if the variant is `Literal`.
148     pub fn is_literal(&self) -> bool {
149         self.literal().is_some()
150     }
151
152     /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
153     pub fn is_word(&self) -> bool {
154         self.meta_item().map_or(false, |meta_item| meta_item.is_word())
155     }
156
157     /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
158     pub fn is_value_str(&self) -> bool {
159         self.value_str().is_some()
160     }
161
162     /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
163     pub fn is_meta_item_list(&self) -> bool {
164         self.meta_item_list().is_some()
165     }
166 }
167
168 impl Attribute {
169     pub fn has_name(&self, name: Symbol) -> bool {
170         match self.kind {
171             AttrKind::Normal(ref item) => item.path == name,
172             AttrKind::DocComment(_) => false,
173         }
174     }
175
176     /// Returns `true` if the attribute's path matches the argument.
177     /// If it matches, then the attribute is marked as used.
178     /// Should only be used by rustc, other tools can use `has_name` instead,
179     /// because only rustc is supposed to report the `unused_attributes` lint.
180     /// `MetaItem` and `NestedMetaItem` are produced by "lowering" an `Attribute`
181     /// and don't have identity, so they only has the `has_name` method,
182     /// and you need to mark the original `Attribute` as used when necessary.
183     pub fn check_name(&self, name: Symbol) -> bool {
184         let matches = self.has_name(name);
185         if matches {
186             mark_used(self);
187         }
188         matches
189     }
190
191     /// For a single-segment attribute, returns its name; otherwise, returns `None`.
192     pub fn ident(&self) -> Option<Ident> {
193         match self.kind {
194             AttrKind::Normal(ref item) => {
195                 if item.path.segments.len() == 1 {
196                     Some(item.path.segments[0].ident)
197                 } else {
198                     None
199                 }
200             }
201             AttrKind::DocComment(_) => None,
202         }
203     }
204     pub fn name_or_empty(&self) -> Symbol {
205         self.ident().unwrap_or(Ident::invalid()).name
206     }
207
208     pub fn value_str(&self) -> Option<Symbol> {
209         match self.kind {
210             AttrKind::Normal(ref item) => item.meta(self.span).and_then(|meta| meta.value_str()),
211             AttrKind::DocComment(..) => None,
212         }
213     }
214
215     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
216         match self.kind {
217             AttrKind::Normal(ref item) => match item.meta(self.span) {
218                 Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
219                 _ => None,
220             },
221             AttrKind::DocComment(_) => None,
222         }
223     }
224
225     pub fn is_word(&self) -> bool {
226         if let AttrKind::Normal(item) = &self.kind {
227             matches!(item.args, MacArgs::Empty)
228         } else {
229             false
230         }
231     }
232
233     pub fn is_meta_item_list(&self) -> bool {
234         self.meta_item_list().is_some()
235     }
236
237     /// Indicates if the attribute is a `ValueString`.
238     pub fn is_value_str(&self) -> bool {
239         self.value_str().is_some()
240     }
241 }
242
243 impl MetaItem {
244     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
245     pub fn ident(&self) -> Option<Ident> {
246         if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
247     }
248     pub fn name_or_empty(&self) -> Symbol {
249         self.ident().unwrap_or(Ident::invalid()).name
250     }
251
252     // Example:
253     //     #[attribute(name = "value")]
254     //                 ^^^^^^^^^^^^^^
255     pub fn name_value_literal(&self) -> Option<&Lit> {
256         match &self.kind {
257             MetaItemKind::NameValue(v) => Some(v),
258             _ => None,
259         }
260     }
261
262     pub fn value_str(&self) -> Option<Symbol> {
263         match self.kind {
264             MetaItemKind::NameValue(ref v) => match v.kind {
265                 LitKind::Str(ref s, _) => Some(*s),
266                 _ => None,
267             },
268             _ => None,
269         }
270     }
271
272     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
273         match self.kind {
274             MetaItemKind::List(ref l) => Some(&l[..]),
275             _ => None,
276         }
277     }
278
279     pub fn is_word(&self) -> bool {
280         match self.kind {
281             MetaItemKind::Word => true,
282             _ => false,
283         }
284     }
285
286     pub fn has_name(&self, name: Symbol) -> bool {
287         self.path == name
288     }
289
290     pub fn is_value_str(&self) -> bool {
291         self.value_str().is_some()
292     }
293
294     pub fn is_meta_item_list(&self) -> bool {
295         self.meta_item_list().is_some()
296     }
297 }
298
299 impl AttrItem {
300     pub fn span(&self) -> Span {
301         self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
302     }
303
304     pub fn meta(&self, span: Span) -> Option<MetaItem> {
305         Some(MetaItem {
306             path: self.path.clone(),
307             kind: MetaItemKind::from_mac_args(&self.args)?,
308             span,
309         })
310     }
311 }
312
313 impl Attribute {
314     pub fn is_doc_comment(&self) -> bool {
315         match self.kind {
316             AttrKind::Normal(_) => false,
317             AttrKind::DocComment(_) => true,
318         }
319     }
320
321     pub fn doc_str(&self) -> Option<Symbol> {
322         match self.kind {
323             AttrKind::DocComment(symbol) => Some(symbol),
324             AttrKind::Normal(ref item) if item.path == sym::doc => {
325                 item.meta(self.span).and_then(|meta| meta.value_str())
326             }
327             _ => None,
328         }
329     }
330
331     pub fn get_normal_item(&self) -> &AttrItem {
332         match self.kind {
333             AttrKind::Normal(ref item) => item,
334             AttrKind::DocComment(_) => panic!("unexpected doc comment"),
335         }
336     }
337
338     pub fn unwrap_normal_item(self) -> AttrItem {
339         match self.kind {
340             AttrKind::Normal(item) => item,
341             AttrKind::DocComment(_) => panic!("unexpected doc comment"),
342         }
343     }
344
345     /// Extracts the MetaItem from inside this Attribute.
346     pub fn meta(&self) -> Option<MetaItem> {
347         match self.kind {
348             AttrKind::Normal(ref item) => item.meta(self.span),
349             AttrKind::DocComment(..) => None,
350         }
351     }
352 }
353
354 /* Constructors */
355
356 pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
357     let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
358     mk_name_value_item(ident, lit_kind, str_span)
359 }
360
361 pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
362     let lit = Lit::from_lit_kind(lit_kind, lit_span);
363     let span = ident.span.to(lit_span);
364     MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
365 }
366
367 pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
368     MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
369 }
370
371 pub fn mk_word_item(ident: Ident) -> MetaItem {
372     MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
373 }
374
375 pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
376     NestedMetaItem::MetaItem(mk_word_item(ident))
377 }
378
379 crate fn mk_attr_id() -> AttrId {
380     use std::sync::atomic::AtomicU32;
381     use std::sync::atomic::Ordering;
382
383     static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0);
384
385     let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
386     assert!(id != u32::MAX);
387     AttrId::from_u32(id)
388 }
389
390 pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
391     mk_attr_from_item(style, AttrItem { path, args }, span)
392 }
393
394 pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute {
395     Attribute { kind: AttrKind::Normal(item), id: mk_attr_id(), style, span }
396 }
397
398 /// Returns an inner attribute with the given value and span.
399 pub fn mk_attr_inner(item: MetaItem) -> Attribute {
400     mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
401 }
402
403 /// Returns an outer attribute with the given value and span.
404 pub fn mk_attr_outer(item: MetaItem) -> Attribute {
405     mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
406 }
407
408 pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute {
409     Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), style, span }
410 }
411
412 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
413     items.iter().any(|item| item.has_name(name))
414 }
415
416 pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
417     attrs.iter().any(|item| item.check_name(name))
418 }
419
420 pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
421     attrs.iter().find(|attr| attr.check_name(name))
422 }
423
424 pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
425     attrs.iter().filter(move |attr| attr.check_name(name))
426 }
427
428 pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
429     attrs.iter().find(|at| at.check_name(name)).and_then(|at| at.value_str())
430 }
431
432 impl MetaItem {
433     fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
434         let mut idents = vec![];
435         let mut last_pos = BytePos(0 as u32);
436         for (i, segment) in self.path.segments.iter().enumerate() {
437             let is_first = i == 0;
438             if !is_first {
439                 let mod_sep_span =
440                     Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt());
441                 idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
442             }
443             idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
444             last_pos = segment.ident.span.hi();
445         }
446         idents.extend(self.kind.token_trees_and_joints(self.span));
447         idents
448     }
449
450     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
451     where
452         I: Iterator<Item = TokenTree>,
453     {
454         // FIXME: Share code with `parse_path`.
455         let path = match tokens.next().map(TokenTree::uninterpolate) {
456             Some(TokenTree::Token(Token {
457                 kind: kind @ (token::Ident(..) | token::ModSep),
458                 span,
459             })) => 'arm: {
460                 let mut segments = if let token::Ident(name, _) = kind {
461                     if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
462                     {
463                         tokens.next();
464                         vec![PathSegment::from_ident(Ident::new(name, span))]
465                     } else {
466                         break 'arm Path::from_ident(Ident::new(name, span));
467                     }
468                 } else {
469                     vec![PathSegment::path_root(span)]
470                 };
471                 loop {
472                     if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) =
473                         tokens.next().map(TokenTree::uninterpolate)
474                     {
475                         segments.push(PathSegment::from_ident(Ident::new(name, span)));
476                     } else {
477                         return None;
478                     }
479                     if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
480                     {
481                         tokens.next();
482                     } else {
483                         break;
484                     }
485                 }
486                 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
487                 Path { span, segments }
488             }
489             Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
490                 token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
491                 token::Nonterminal::NtPath(ref path) => path.clone(),
492                 _ => return None,
493             },
494             _ => return None,
495         };
496         let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
497         let kind = MetaItemKind::from_tokens(tokens)?;
498         let hi = match kind {
499             MetaItemKind::NameValue(ref lit) => lit.span.hi(),
500             MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
501             _ => path.span.hi(),
502         };
503         let span = path.span.with_hi(hi);
504         Some(MetaItem { path, kind, span })
505     }
506 }
507
508 impl MetaItemKind {
509     pub fn mac_args(&self, span: Span) -> MacArgs {
510         match self {
511             MetaItemKind::Word => MacArgs::Empty,
512             MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()),
513             MetaItemKind::List(list) => {
514                 let mut tts = Vec::new();
515                 for (i, item) in list.iter().enumerate() {
516                     if i > 0 {
517                         tts.push(TokenTree::token(token::Comma, span).into());
518                     }
519                     tts.extend(item.token_trees_and_joints())
520                 }
521                 MacArgs::Delimited(
522                     DelimSpan::from_single(span),
523                     MacDelimiter::Parenthesis,
524                     TokenStream::new(tts),
525                 )
526             }
527         }
528     }
529
530     fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> {
531         match *self {
532             MetaItemKind::Word => vec![],
533             MetaItemKind::NameValue(ref lit) => {
534                 vec![TokenTree::token(token::Eq, span).into(), lit.token_tree().into()]
535             }
536             MetaItemKind::List(ref list) => {
537                 let mut tokens = Vec::new();
538                 for (i, item) in list.iter().enumerate() {
539                     if i > 0 {
540                         tokens.push(TokenTree::token(token::Comma, span).into());
541                     }
542                     tokens.extend(item.token_trees_and_joints())
543                 }
544                 vec![
545                     TokenTree::Delimited(
546                         DelimSpan::from_single(span),
547                         token::Paren,
548                         TokenStream::new(tokens),
549                     )
550                     .into(),
551                 ]
552             }
553         }
554     }
555
556     fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
557         let mut tokens = tokens.into_trees().peekable();
558         let mut result = Vec::new();
559         while let Some(..) = tokens.peek() {
560             let item = NestedMetaItem::from_tokens(&mut tokens)?;
561             result.push(item);
562             match tokens.next() {
563                 None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {}
564                 _ => return None,
565             }
566         }
567         Some(MetaItemKind::List(result))
568     }
569
570     fn name_value_from_tokens(
571         tokens: &mut impl Iterator<Item = TokenTree>,
572     ) -> Option<MetaItemKind> {
573         match tokens.next() {
574             Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
575                 MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
576             }
577             Some(TokenTree::Token(token)) => {
578                 Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
579             }
580             _ => None,
581         }
582     }
583
584     fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
585         match args {
586             MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => {
587                 MetaItemKind::list_from_tokens(tokens.clone())
588             }
589             MacArgs::Delimited(..) => None,
590             MacArgs::Eq(_, tokens) => {
591                 assert!(tokens.len() == 1);
592                 MetaItemKind::name_value_from_tokens(&mut tokens.trees())
593             }
594             MacArgs::Empty => Some(MetaItemKind::Word),
595         }
596     }
597
598     fn from_tokens(
599         tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
600     ) -> Option<MetaItemKind> {
601         match tokens.peek() {
602             Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => {
603                 let inner_tokens = inner_tokens.clone();
604                 tokens.next();
605                 MetaItemKind::list_from_tokens(inner_tokens)
606             }
607             Some(TokenTree::Delimited(..)) => None,
608             Some(TokenTree::Token(Token { kind: token::Eq, .. })) => {
609                 tokens.next();
610                 MetaItemKind::name_value_from_tokens(tokens)
611             }
612             _ => Some(MetaItemKind::Word),
613         }
614     }
615 }
616
617 impl NestedMetaItem {
618     pub fn span(&self) -> Span {
619         match *self {
620             NestedMetaItem::MetaItem(ref item) => item.span,
621             NestedMetaItem::Literal(ref lit) => lit.span,
622         }
623     }
624
625     fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
626         match *self {
627             NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(),
628             NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()],
629         }
630     }
631
632     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
633     where
634         I: Iterator<Item = TokenTree>,
635     {
636         match tokens.peek() {
637             Some(TokenTree::Token(token)) => {
638                 if let Ok(lit) = Lit::from_token(token) {
639                     tokens.next();
640                     return Some(NestedMetaItem::Literal(lit));
641                 }
642             }
643             Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
644                 let inner_tokens = inner_tokens.clone();
645                 tokens.next();
646                 return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable());
647             }
648             _ => {}
649         }
650         MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
651     }
652 }
653
654 pub trait HasAttrs: Sized {
655     fn attrs(&self) -> &[Attribute];
656     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
657 }
658
659 impl<T: HasAttrs> HasAttrs for Spanned<T> {
660     fn attrs(&self) -> &[Attribute] {
661         self.node.attrs()
662     }
663     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
664         self.node.visit_attrs(f);
665     }
666 }
667
668 impl HasAttrs for Vec<Attribute> {
669     fn attrs(&self) -> &[Attribute] {
670         self
671     }
672     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
673         f(self)
674     }
675 }
676
677 impl HasAttrs for AttrVec {
678     fn attrs(&self) -> &[Attribute] {
679         self
680     }
681     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
682         visit_clobber(self, |this| {
683             let mut vec = this.into();
684             f(&mut vec);
685             vec.into()
686         });
687     }
688 }
689
690 impl<T: HasAttrs + 'static> HasAttrs for P<T> {
691     fn attrs(&self) -> &[Attribute] {
692         (**self).attrs()
693     }
694     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
695         (**self).visit_attrs(f);
696     }
697 }
698
699 impl HasAttrs for StmtKind {
700     fn attrs(&self) -> &[Attribute] {
701         match *self {
702             StmtKind::Local(ref local) => local.attrs(),
703             StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
704             StmtKind::Empty | StmtKind::Item(..) => &[],
705             StmtKind::MacCall(ref mac) => {
706                 let (_, _, ref attrs) = **mac;
707                 attrs.attrs()
708             }
709         }
710     }
711
712     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
713         match self {
714             StmtKind::Local(local) => local.visit_attrs(f),
715             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
716             StmtKind::Empty | StmtKind::Item(..) => {}
717             StmtKind::MacCall(mac) => {
718                 let (_mac, _style, attrs) = mac.deref_mut();
719                 attrs.visit_attrs(f);
720             }
721         }
722     }
723 }
724
725 impl HasAttrs for Stmt {
726     fn attrs(&self) -> &[ast::Attribute] {
727         self.kind.attrs()
728     }
729
730     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
731         self.kind.visit_attrs(f);
732     }
733 }
734
735 macro_rules! derive_has_attrs {
736     ($($ty:path),*) => { $(
737         impl HasAttrs for $ty {
738             fn attrs(&self) -> &[Attribute] {
739                 &self.attrs
740             }
741
742             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
743                 self.attrs.visit_attrs(f);
744             }
745         }
746     )* }
747 }
748
749 derive_has_attrs! {
750     Item, Expr, Local, ast::AssocItem, ast::ForeignItem, ast::StructField, ast::Arm,
751     ast::Field, ast::FieldPat, ast::Variant, ast::Param, GenericParam
752 }