]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/attr/mod.rs
Account for `ty::Error` when suggesting `impl Trait` or `Box<dyn Trait>`
[rust.git] / src / libsyntax / attr / mod.rs
1 //! Functions dealing with attributes and meta items.
2
3 mod builtin;
4
5 pub use crate::ast::Attribute;
6 pub use builtin::*;
7 pub use IntType::*;
8 pub use ReprAttr::*;
9 pub use StabilityLevel::*;
10
11 use crate::ast;
12 use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Ident, Name, Path, PathSegment};
13 use crate::ast::{Expr, GenericParam, Item, Lit, LitKind, Local, Stmt, StmtKind};
14 use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
15 use crate::mut_visit::visit_clobber;
16 use crate::ptr::P;
17 use crate::token::{self, Token};
18 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
19 use crate::GLOBALS;
20
21 use rustc_span::source_map::{BytePos, Spanned};
22 use rustc_span::symbol::{sym, Symbol};
23 use rustc_span::Span;
24
25 use log::debug;
26 use std::iter;
27 use std::ops::DerefMut;
28
29 pub fn mark_used(attr: &Attribute) {
30     debug!("marking {:?} as used", attr);
31     GLOBALS.with(|globals| {
32         globals.used_attrs.lock().insert(attr.id);
33     });
34 }
35
36 pub fn is_used(attr: &Attribute) -> bool {
37     GLOBALS.with(|globals| globals.used_attrs.lock().contains(attr.id))
38 }
39
40 pub fn mark_known(attr: &Attribute) {
41     debug!("marking {:?} as known", attr);
42     GLOBALS.with(|globals| {
43         globals.known_attrs.lock().insert(attr.id);
44     });
45 }
46
47 pub fn is_known(attr: &Attribute) -> bool {
48     GLOBALS.with(|globals| globals.known_attrs.lock().contains(attr.id))
49 }
50
51 pub fn is_known_lint_tool(m_item: Ident) -> bool {
52     [sym::clippy, sym::rustc].contains(&m_item.name)
53 }
54
55 impl NestedMetaItem {
56     /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
57     pub fn meta_item(&self) -> Option<&MetaItem> {
58         match *self {
59             NestedMetaItem::MetaItem(ref item) => Some(item),
60             _ => None,
61         }
62     }
63
64     /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
65     pub fn literal(&self) -> Option<&Lit> {
66         match *self {
67             NestedMetaItem::Literal(ref lit) => Some(lit),
68             _ => None,
69         }
70     }
71
72     /// Returns `true` if this list item is a MetaItem with a name of `name`.
73     pub fn check_name(&self, name: Symbol) -> bool {
74         self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
75     }
76
77     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
78     pub fn ident(&self) -> Option<Ident> {
79         self.meta_item().and_then(|meta_item| meta_item.ident())
80     }
81     pub fn name_or_empty(&self) -> Symbol {
82         self.ident().unwrap_or(Ident::invalid()).name
83     }
84
85     /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
86     /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
87     pub fn value_str(&self) -> Option<Symbol> {
88         self.meta_item().and_then(|meta_item| meta_item.value_str())
89     }
90
91     /// Returns a name and single literal value tuple of the `MetaItem`.
92     pub fn name_value_literal(&self) -> Option<(Name, &Lit)> {
93         self.meta_item().and_then(|meta_item| {
94             meta_item.meta_item_list().and_then(|meta_item_list| {
95                 if meta_item_list.len() == 1 {
96                     if let Some(ident) = meta_item.ident() {
97                         if let Some(lit) = meta_item_list[0].literal() {
98                             return Some((ident.name, lit));
99                         }
100                     }
101                 }
102                 None
103             })
104         })
105     }
106
107     /// Gets a list of inner meta items from a list `MetaItem` type.
108     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
109         self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
110     }
111
112     /// Returns `true` if the variant is `MetaItem`.
113     pub fn is_meta_item(&self) -> bool {
114         self.meta_item().is_some()
115     }
116
117     /// Returns `true` if the variant is `Literal`.
118     pub fn is_literal(&self) -> bool {
119         self.literal().is_some()
120     }
121
122     /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
123     pub fn is_word(&self) -> bool {
124         self.meta_item().map_or(false, |meta_item| meta_item.is_word())
125     }
126
127     /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
128     pub fn is_value_str(&self) -> bool {
129         self.value_str().is_some()
130     }
131
132     /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
133     pub fn is_meta_item_list(&self) -> bool {
134         self.meta_item_list().is_some()
135     }
136 }
137
138 impl Attribute {
139     pub fn has_name(&self, name: Symbol) -> bool {
140         match self.kind {
141             AttrKind::Normal(ref item) => item.path == name,
142             AttrKind::DocComment(_) => false,
143         }
144     }
145
146     /// Returns `true` if the attribute's path matches the argument. If it matches, then the
147     /// attribute is marked as used.
148     pub fn check_name(&self, name: Symbol) -> bool {
149         let matches = self.has_name(name);
150         if matches {
151             mark_used(self);
152         }
153         matches
154     }
155
156     /// For a single-segment attribute, returns its name; otherwise, returns `None`.
157     pub fn ident(&self) -> Option<Ident> {
158         match self.kind {
159             AttrKind::Normal(ref item) => {
160                 if item.path.segments.len() == 1 {
161                     Some(item.path.segments[0].ident)
162                 } else {
163                     None
164                 }
165             }
166             AttrKind::DocComment(_) => None,
167         }
168     }
169     pub fn name_or_empty(&self) -> Symbol {
170         self.ident().unwrap_or(Ident::invalid()).name
171     }
172
173     pub fn value_str(&self) -> Option<Symbol> {
174         match self.kind {
175             AttrKind::Normal(ref item) => item.meta(self.span).and_then(|meta| meta.value_str()),
176             AttrKind::DocComment(..) => None,
177         }
178     }
179
180     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
181         match self.kind {
182             AttrKind::Normal(ref item) => match item.meta(self.span) {
183                 Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
184                 _ => None,
185             },
186             AttrKind::DocComment(_) => None,
187         }
188     }
189
190     pub fn is_word(&self) -> bool {
191         if let AttrKind::Normal(item) = &self.kind {
192             matches!(item.args, MacArgs::Empty)
193         } else {
194             false
195         }
196     }
197
198     pub fn is_meta_item_list(&self) -> bool {
199         self.meta_item_list().is_some()
200     }
201
202     /// Indicates if the attribute is a `ValueString`.
203     pub fn is_value_str(&self) -> bool {
204         self.value_str().is_some()
205     }
206 }
207
208 impl MetaItem {
209     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
210     pub fn ident(&self) -> Option<Ident> {
211         if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
212     }
213     pub fn name_or_empty(&self) -> Symbol {
214         self.ident().unwrap_or(Ident::invalid()).name
215     }
216
217     // Example:
218     //     #[attribute(name = "value")]
219     //                 ^^^^^^^^^^^^^^
220     pub fn name_value_literal(&self) -> Option<&Lit> {
221         match &self.kind {
222             MetaItemKind::NameValue(v) => Some(v),
223             _ => None,
224         }
225     }
226
227     pub fn value_str(&self) -> Option<Symbol> {
228         match self.kind {
229             MetaItemKind::NameValue(ref v) => match v.kind {
230                 LitKind::Str(ref s, _) => Some(*s),
231                 _ => None,
232             },
233             _ => None,
234         }
235     }
236
237     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
238         match self.kind {
239             MetaItemKind::List(ref l) => Some(&l[..]),
240             _ => None,
241         }
242     }
243
244     pub fn is_word(&self) -> bool {
245         match self.kind {
246             MetaItemKind::Word => true,
247             _ => false,
248         }
249     }
250
251     pub fn check_name(&self, name: Symbol) -> bool {
252         self.path == name
253     }
254
255     pub fn is_value_str(&self) -> bool {
256         self.value_str().is_some()
257     }
258
259     pub fn is_meta_item_list(&self) -> bool {
260         self.meta_item_list().is_some()
261     }
262 }
263
264 impl AttrItem {
265     pub fn meta(&self, span: Span) -> Option<MetaItem> {
266         Some(MetaItem {
267             path: self.path.clone(),
268             kind: MetaItemKind::from_mac_args(&self.args)?,
269             span,
270         })
271     }
272 }
273
274 impl Attribute {
275     pub fn is_doc_comment(&self) -> bool {
276         match self.kind {
277             AttrKind::Normal(_) => false,
278             AttrKind::DocComment(_) => true,
279         }
280     }
281
282     pub fn doc_str(&self) -> Option<Symbol> {
283         match self.kind {
284             AttrKind::DocComment(symbol) => Some(symbol),
285             AttrKind::Normal(ref item) if item.path == sym::doc => {
286                 item.meta(self.span).and_then(|meta| meta.value_str())
287             }
288             _ => None,
289         }
290     }
291
292     pub fn get_normal_item(&self) -> &AttrItem {
293         match self.kind {
294             AttrKind::Normal(ref item) => item,
295             AttrKind::DocComment(_) => panic!("unexpected doc comment"),
296         }
297     }
298
299     pub fn unwrap_normal_item(self) -> AttrItem {
300         match self.kind {
301             AttrKind::Normal(item) => item,
302             AttrKind::DocComment(_) => panic!("unexpected doc comment"),
303         }
304     }
305
306     /// Extracts the MetaItem from inside this Attribute.
307     pub fn meta(&self) -> Option<MetaItem> {
308         match self.kind {
309             AttrKind::Normal(ref item) => item.meta(self.span),
310             AttrKind::DocComment(..) => None,
311         }
312     }
313 }
314
315 /* Constructors */
316
317 pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
318     let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
319     mk_name_value_item(ident, lit_kind, str_span)
320 }
321
322 pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
323     let lit = Lit::from_lit_kind(lit_kind, lit_span);
324     let span = ident.span.to(lit_span);
325     MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
326 }
327
328 pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
329     MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
330 }
331
332 pub fn mk_word_item(ident: Ident) -> MetaItem {
333     MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
334 }
335
336 pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
337     NestedMetaItem::MetaItem(mk_word_item(ident))
338 }
339
340 crate fn mk_attr_id() -> AttrId {
341     use std::sync::atomic::AtomicUsize;
342     use std::sync::atomic::Ordering;
343
344     static NEXT_ATTR_ID: AtomicUsize = AtomicUsize::new(0);
345
346     let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
347     assert!(id != ::std::usize::MAX);
348     AttrId(id)
349 }
350
351 pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
352     mk_attr_from_item(style, AttrItem { path, args }, span)
353 }
354
355 pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute {
356     Attribute { kind: AttrKind::Normal(item), id: mk_attr_id(), style, span }
357 }
358
359 /// Returns an inner attribute with the given value and span.
360 pub fn mk_attr_inner(item: MetaItem) -> Attribute {
361     mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
362 }
363
364 /// Returns an outer attribute with the given value and span.
365 pub fn mk_attr_outer(item: MetaItem) -> Attribute {
366     mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
367 }
368
369 pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute {
370     Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), style, span }
371 }
372
373 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
374     items.iter().any(|item| item.check_name(name))
375 }
376
377 pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
378     attrs.iter().any(|item| item.check_name(name))
379 }
380
381 pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
382     attrs.iter().find(|attr| attr.check_name(name))
383 }
384
385 pub fn allow_internal_unstable<'a>(
386     attrs: &[Attribute],
387     span_diagnostic: &'a rustc_errors::Handler,
388 ) -> Option<impl Iterator<Item = Symbol> + 'a> {
389     find_by_name(attrs, sym::allow_internal_unstable).and_then(|attr| {
390         attr.meta_item_list()
391             .or_else(|| {
392                 span_diagnostic
393                     .span_err(attr.span, "allow_internal_unstable expects list of feature names");
394                 None
395             })
396             .map(|features| {
397                 features.into_iter().filter_map(move |it| {
398                     let name = it.ident().map(|ident| ident.name);
399                     if name.is_none() {
400                         span_diagnostic
401                             .span_err(it.span(), "`allow_internal_unstable` expects feature names")
402                     }
403                     name
404                 })
405             })
406     })
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).into(),
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) -> &[ast::Attribute];
630     fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
631 }
632
633 impl<T: HasAttrs> HasAttrs for Spanned<T> {
634     fn attrs(&self) -> &[ast::Attribute] {
635         self.node.attrs()
636     }
637     fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
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<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
647         f(self)
648     }
649 }
650
651 impl HasAttrs for AttrVec {
652     fn attrs(&self) -> &[Attribute] {
653         self
654     }
655     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
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<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
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<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
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<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
706         self.kind.visit_attrs(f);
707     }
708 }
709
710 impl HasAttrs for GenericParam {
711     fn attrs(&self) -> &[ast::Attribute] {
712         &self.attrs
713     }
714
715     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
716         self.attrs.visit_attrs(f);
717     }
718 }
719
720 macro_rules! derive_has_attrs {
721     ($($ty:path),*) => { $(
722         impl HasAttrs for $ty {
723             fn attrs(&self) -> &[Attribute] {
724                 &self.attrs
725             }
726
727             fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
728                 self.attrs.visit_attrs(f);
729             }
730         }
731     )* }
732 }
733
734 derive_has_attrs! {
735     Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::AssocItem, ast::Arm,
736     ast::Field, ast::FieldPat, ast::Variant, ast::Param
737 }