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