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