1 //! Functions dealing with attributes and meta items
6 cfg_matches, contains_feature_attr, eval_condition, find_crate_name, find_deprecation,
7 find_repr_attrs, find_stability, find_unwind_attr, Deprecation, InlineAttr, OptimizeAttr,
8 IntType, ReprAttr, RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
12 pub use StabilityLevel::*;
15 use crate::ast::{AttrId, Attribute, AttrStyle, Name, Ident, Path, PathSegment};
16 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
17 use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
18 use crate::mut_visit::visit_clobber;
19 use crate::source_map::{BytePos, Spanned, dummy_spanned};
20 use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
21 use crate::parse::parser::Parser;
22 use crate::parse::{self, ParseSess, PResult};
23 use crate::parse::token::{self, Token};
25 use crate::symbol::{keywords, LocalInternedString, Symbol};
27 use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
32 use syntax_pos::{FileName, Span};
36 use std::ops::DerefMut;
38 pub fn mark_used(attr: &Attribute) {
39 debug!("Marking {:?} as used.", attr);
40 GLOBALS.with(|globals| {
41 globals.used_attrs.lock().insert(attr.id);
45 pub fn is_used(attr: &Attribute) -> bool {
46 GLOBALS.with(|globals| {
47 globals.used_attrs.lock().contains(attr.id)
51 pub fn mark_known(attr: &Attribute) {
52 debug!("Marking {:?} as known.", attr);
53 GLOBALS.with(|globals| {
54 globals.known_attrs.lock().insert(attr.id);
58 pub fn is_known(attr: &Attribute) -> bool {
59 GLOBALS.with(|globals| {
60 globals.known_attrs.lock().contains(attr.id)
64 pub fn is_known_lint_tool(m_item: Ident) -> bool {
65 ["clippy"].contains(&m_item.as_str().as_ref())
69 /// Returns the MetaItem if self is a NestedMetaItem::MetaItem.
70 pub fn meta_item(&self) -> Option<&MetaItem> {
72 NestedMetaItem::MetaItem(ref item) => Some(item),
77 /// Returns the Lit if self is a NestedMetaItem::Literal.
78 pub fn literal(&self) -> Option<&Lit> {
80 NestedMetaItem::Literal(ref lit) => Some(lit),
85 /// Returns `true` if this list item is a MetaItem with a name of `name`.
86 pub fn check_name<T>(&self, name: T) -> bool
90 self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
93 /// For a single-segment meta-item returns its name, otherwise returns `None`.
94 pub fn ident(&self) -> Option<Ident> {
95 self.meta_item().and_then(|meta_item| meta_item.ident())
97 pub fn name_or_empty(&self) -> LocalInternedString {
98 self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
101 /// Gets the string value if self is a MetaItem and the MetaItem is a
102 /// MetaItemKind::NameValue variant containing a string, otherwise None.
103 pub fn value_str(&self) -> Option<Symbol> {
104 self.meta_item().and_then(|meta_item| meta_item.value_str())
107 /// Returns a name and single literal value tuple of the MetaItem.
108 pub fn name_value_literal(&self) -> Option<(Name, &Lit)> {
109 self.meta_item().and_then(
110 |meta_item| meta_item.meta_item_list().and_then(
112 if meta_item_list.len() == 1 {
113 if let Some(ident) = meta_item.ident() {
114 if let Some(lit) = meta_item_list[0].literal() {
115 return Some((ident.name, lit));
123 /// Gets a list of inner meta items from a list MetaItem type.
124 pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
125 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
128 /// Returns `true` if the variant is MetaItem.
129 pub fn is_meta_item(&self) -> bool {
130 self.meta_item().is_some()
133 /// Returns `true` if the variant is Literal.
134 pub fn is_literal(&self) -> bool {
135 self.literal().is_some()
138 /// Returns `true` if self is a MetaItem and the meta item is a word.
139 pub fn is_word(&self) -> bool {
140 self.meta_item().map_or(false, |meta_item| meta_item.is_word())
143 /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
144 pub fn is_value_str(&self) -> bool {
145 self.value_str().is_some()
148 /// Returns `true` if self is a MetaItem and the meta item is a list.
149 pub fn is_meta_item_list(&self) -> bool {
150 self.meta_item_list().is_some()
155 /// Returns `true` if the attribute's path matches the argument. If it matches, then the
156 /// attribute is marked as used.
158 /// To check the attribute name without marking it used, use the `path` field directly.
159 pub fn check_name<T>(&self, name: T) -> bool
163 let matches = self.path == name;
170 /// For a single-segment attribute returns its name, otherwise returns `None`.
171 pub fn ident(&self) -> Option<Ident> {
172 if self.path.segments.len() == 1 {
173 Some(self.path.segments[0].ident)
178 pub fn name_or_empty(&self) -> LocalInternedString {
179 self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
182 pub fn value_str(&self) -> Option<Symbol> {
183 self.meta().and_then(|meta| meta.value_str())
186 pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
188 Some(MetaItem { node: MetaItemKind::List(list), .. }) => Some(list),
193 pub fn is_word(&self) -> bool {
194 self.tokens.is_empty()
197 pub fn is_meta_item_list(&self) -> bool {
198 self.meta_item_list().is_some()
201 /// Indicates if the attribute is a Value String.
202 pub fn is_value_str(&self) -> bool {
203 self.value_str().is_some()
208 /// For a single-segment meta-item returns its name, otherwise returns `None`.
209 pub fn ident(&self) -> Option<Ident> {
210 if self.path.segments.len() == 1 {
211 Some(self.path.segments[0].ident)
216 pub fn name_or_empty(&self) -> LocalInternedString {
217 self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
220 // #[attribute(name = "value")]
222 pub fn name_value_literal(&self) -> Option<&Lit> {
224 MetaItemKind::NameValue(v) => Some(v),
229 pub fn value_str(&self) -> Option<Symbol> {
231 MetaItemKind::NameValue(ref v) => {
233 LitKind::Str(ref s, _) => Some(*s),
241 pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
243 MetaItemKind::List(ref l) => Some(&l[..]),
248 pub fn is_word(&self) -> bool {
250 MetaItemKind::Word => true,
255 pub fn check_name<T>(&self, name: T) -> bool
262 pub fn is_value_str(&self) -> bool {
263 self.value_str().is_some()
266 pub fn is_meta_item_list(&self) -> bool {
267 self.meta_item_list().is_some()
272 /// Extracts the MetaItem from inside this Attribute.
273 pub fn meta(&self) -> Option<MetaItem> {
274 let mut tokens = self.tokens.trees().peekable();
276 path: self.path.clone(),
277 node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) {
278 if tokens.peek().is_some() {
289 pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
290 where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
292 let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
293 let result = f(&mut parser)?;
294 if parser.token != token::Eof {
295 parser.unexpected()?;
300 pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec<T>>
301 where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
303 if self.tokens.is_empty() {
304 return Ok(Vec::new());
306 self.parse(sess, |parser| {
307 parser.expect(&token::OpenDelim(token::Paren))?;
308 let mut list = Vec::new();
309 while !parser.eat(&token::CloseDelim(token::Paren)) {
310 list.push(f(parser)?);
311 if !parser.eat(&token::Comma) {
312 parser.expect(&token::CloseDelim(token::Paren))?;
320 pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
322 path: self.path.clone(),
323 node: self.parse(sess, |parser| parser.parse_meta_item_kind())?,
328 /// Converts self to a normal #[doc="foo"] comment, if it is a
329 /// comment like `///` or `/** */`. (Returns self unchanged for
330 /// non-sugared doc attributes.)
331 pub fn with_desugared_doc<T, F>(&self, f: F) -> T where
332 F: FnOnce(&Attribute) -> T,
334 if self.is_sugared_doc {
335 let comment = self.value_str().unwrap();
336 let meta = mk_name_value_item_str(
337 Ident::from_str("doc"),
338 dummy_spanned(Symbol::intern(&strip_doc_comment_decoration(&comment.as_str()))));
339 let mut attr = if self.style == ast::AttrStyle::Outer {
340 mk_attr_outer(self.span, self.id, meta)
342 mk_attr_inner(self.span, self.id, meta)
344 attr.is_sugared_doc = true;
354 pub fn mk_name_value_item_str(ident: Ident, value: Spanned<Symbol>) -> MetaItem {
355 let lit_kind = LitKind::Str(value.node, ast::StrStyle::Cooked);
356 mk_name_value_item(ident.span.to(value.span), ident, lit_kind, value.span)
359 pub fn mk_name_value_item(span: Span, ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
360 let lit = Lit::from_lit_kind(lit_kind, lit_span);
361 MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(lit) }
364 pub fn mk_list_item(span: Span, ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
365 MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::List(items) }
368 pub fn mk_word_item(ident: Ident) -> MetaItem {
369 MetaItem { path: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word }
372 pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
373 NestedMetaItem::MetaItem(mk_word_item(ident))
376 pub fn mk_attr_id() -> AttrId {
377 use std::sync::atomic::AtomicUsize;
378 use std::sync::atomic::Ordering;
380 static NEXT_ATTR_ID: AtomicUsize = AtomicUsize::new(0);
382 let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
383 assert!(id != ::std::usize::MAX);
387 /// Returns an inner attribute with the given value.
388 pub fn mk_attr_inner(span: Span, id: AttrId, item: MetaItem) -> Attribute {
389 mk_spanned_attr_inner(span, id, item)
392 /// Returns an inner attribute with the given value and span.
393 pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute {
396 style: ast::AttrStyle::Inner,
398 tokens: item.node.tokens(item.span),
399 is_sugared_doc: false,
404 /// Returns an outer attribute with the given value.
405 pub fn mk_attr_outer(span: Span, id: AttrId, item: MetaItem) -> Attribute {
406 mk_spanned_attr_outer(span, id, item)
409 /// Returns an outer attribute with the given value and span.
410 pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute {
413 style: ast::AttrStyle::Outer,
415 tokens: item.node.tokens(item.span),
416 is_sugared_doc: false,
421 pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute {
422 let style = doc_comment_style(&text.as_str());
423 let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
424 let lit = Lit::from_lit_kind(lit_kind, span);
428 path: Path::from_ident(Ident::from_str("doc").with_span_pos(span)),
429 tokens: MetaItemKind::NameValue(lit).tokens(span),
430 is_sugared_doc: true,
435 pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool {
436 items.iter().any(|item| {
437 item.check_name(name)
441 pub fn contains_name(attrs: &[Attribute], name: &str) -> bool {
442 attrs.iter().any(|item| {
443 item.check_name(name)
447 pub fn find_by_name<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> {
448 attrs.iter().find(|attr| attr.check_name(name))
451 pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: &'a str)
452 -> impl Iterator<Item = &'a Attribute> {
453 attrs.iter().filter(move |attr| attr.check_name(name))
456 pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<Symbol> {
458 .find(|at| at.check_name(name))
459 .and_then(|at| at.value_str())
463 fn tokens(&self) -> TokenStream {
464 let mut idents = vec![];
465 let mut last_pos = BytePos(0 as u32);
466 for (i, segment) in self.path.segments.iter().enumerate() {
467 let is_first = i == 0;
469 let mod_sep_span = Span::new(last_pos,
470 segment.ident.span.lo(),
471 segment.ident.span.ctxt());
472 idents.push(TokenTree::Token(mod_sep_span, Token::ModSep).into());
474 idents.push(TokenTree::Token(segment.ident.span,
475 Token::from_ast_ident(segment.ident)).into());
476 last_pos = segment.ident.span.hi();
478 self.node.tokens(self.span).append_to_tree_and_joint_vec(&mut idents);
479 TokenStream::new(idents)
482 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
483 where I: Iterator<Item = TokenTree>,
485 // FIXME: Share code with `parse_path`.
486 let path = match tokens.next() {
487 Some(TokenTree::Token(span, token @ Token::Ident(..))) |
488 Some(TokenTree::Token(span, token @ Token::ModSep)) => 'arm: {
489 let mut segments = if let Token::Ident(ident, _) = token {
490 if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() {
492 vec![PathSegment::from_ident(ident.with_span_pos(span))]
494 break 'arm Path::from_ident(ident.with_span_pos(span));
497 vec![PathSegment::path_root(span)]
500 if let Some(TokenTree::Token(span,
501 Token::Ident(ident, _))) = tokens.next() {
502 segments.push(PathSegment::from_ident(ident.with_span_pos(span)));
506 if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() {
512 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
513 Path { span, segments }
515 Some(TokenTree::Token(_, Token::Interpolated(nt))) => match *nt {
516 token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
517 token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
518 token::Nonterminal::NtPath(ref path) => path.clone(),
523 let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
524 let node = MetaItemKind::from_tokens(tokens)?;
525 let hi = match node {
526 MetaItemKind::NameValue(ref lit) => lit.span.hi(),
527 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
530 let span = path.span.with_hi(hi);
531 Some(MetaItem { path, node, span })
536 pub fn tokens(&self, span: Span) -> TokenStream {
538 MetaItemKind::Word => TokenStream::empty(),
539 MetaItemKind::NameValue(ref lit) => {
540 let mut vec = vec![TokenTree::Token(span, Token::Eq).into()];
541 lit.tokens().append_to_tree_and_joint_vec(&mut vec);
542 TokenStream::new(vec)
544 MetaItemKind::List(ref list) => {
545 let mut tokens = Vec::new();
546 for (i, item) in list.iter().enumerate() {
548 tokens.push(TokenTree::Token(span, Token::Comma).into());
550 item.tokens().append_to_tree_and_joint_vec(&mut tokens);
552 TokenTree::Delimited(
553 DelimSpan::from_single(span),
555 TokenStream::new(tokens).into(),
561 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind>
562 where I: Iterator<Item = TokenTree>,
564 let delimited = match tokens.peek().cloned() {
565 Some(TokenTree::Token(_, token::Eq)) => {
567 return if let Some(TokenTree::Token(span, token)) = tokens.next() {
568 Lit::from_token(&token, span, None).map(MetaItemKind::NameValue)
573 Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => {
577 _ => return Some(MetaItemKind::Word),
580 let mut tokens = delimited.into_trees().peekable();
581 let mut result = Vec::new();
582 while let Some(..) = tokens.peek() {
583 let item = NestedMetaItem::from_tokens(&mut tokens)?;
585 match tokens.next() {
586 None | Some(TokenTree::Token(_, Token::Comma)) => {}
590 Some(MetaItemKind::List(result))
594 impl NestedMetaItem {
595 pub fn span(&self) -> Span {
597 NestedMetaItem::MetaItem(ref item) => item.span,
598 NestedMetaItem::Literal(ref lit) => lit.span,
602 fn tokens(&self) -> TokenStream {
604 NestedMetaItem::MetaItem(ref item) => item.tokens(),
605 NestedMetaItem::Literal(ref lit) => lit.tokens(),
609 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
610 where I: Iterator<Item = TokenTree>,
612 if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() {
613 if let Some(lit) = Lit::from_token(&token, span, None) {
615 return Some(NestedMetaItem::Literal(lit));
619 MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
624 crate fn tokens(&self) -> TokenStream {
625 let token = match self.token {
626 token::Bool(symbol) => Token::Ident(Ident::with_empty_ctxt(symbol), false),
627 token => Token::Literal(token, self.suffix),
629 TokenTree::Token(self.span, token).into()
634 /// Attempts to recover a token from semantic literal.
635 /// This function is used when the original token doesn't exist (e.g. the literal is created
636 /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
637 pub fn to_lit_token(&self) -> (token::Lit, Option<Symbol>) {
639 LitKind::Str(string, ast::StrStyle::Cooked) => {
640 let escaped = string.as_str().escape_default().to_string();
641 (token::Lit::Str_(Symbol::intern(&escaped)), None)
643 LitKind::Str(string, ast::StrStyle::Raw(n)) => {
644 (token::Lit::StrRaw(string, n), None)
646 LitKind::ByteStr(ref bytes) => {
647 let string = bytes.iter().cloned().flat_map(ascii::escape_default)
648 .map(Into::<char>::into).collect::<String>();
649 (token::Lit::ByteStr(Symbol::intern(&string)), None)
651 LitKind::Byte(byte) => {
652 let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
653 (token::Lit::Byte(Symbol::intern(&string)), None)
655 LitKind::Char(ch) => {
656 let string: String = ch.escape_default().map(Into::<char>::into).collect();
657 (token::Lit::Char(Symbol::intern(&string)), None)
659 LitKind::Int(n, ty) => {
660 let suffix = match ty {
661 ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())),
662 ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())),
663 ast::LitIntType::Unsuffixed => None,
665 (token::Lit::Integer(Symbol::intern(&n.to_string())), suffix)
667 LitKind::Float(symbol, ty) => {
668 (token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string())))
670 LitKind::FloatUnsuffixed(symbol) => (token::Lit::Float(symbol), None),
671 LitKind::Bool(value) => {
672 let kw = if value { keywords::True } else { keywords::False };
673 (token::Lit::Bool(kw.name()), None)
675 LitKind::Err(val) => (token::Lit::Err(val), None),
681 /// Converts literal token with a suffix into an AST literal.
682 /// Works speculatively and may return `None` is diagnostic handler is not passed.
683 /// If diagnostic handler is passed, may return `Some`,
684 /// possibly after reporting non-fatal errors and recovery, or `None` for irrecoverable errors.
686 token: &token::Token,
688 diag: Option<(Span, &Handler)>,
690 let (token, suffix) = match *token {
691 token::Ident(ident, false) if ident.name == keywords::True.name() ||
692 ident.name == keywords::False.name() =>
693 (token::Bool(ident.name), None),
694 token::Literal(token, suffix) =>
696 token::Interpolated(ref nt) => {
697 if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
698 if let ast::ExprKind::Lit(lit) = &expr.node {
699 return Some(lit.clone());
707 let node = LitKind::from_lit_token(token, suffix, diag)?;
708 Some(Lit { node, token, suffix, span })
711 /// Attempts to recover an AST literal from semantic literal.
712 /// This function is used when the original token doesn't exist (e.g. the literal is created
713 /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
714 pub fn from_lit_kind(node: LitKind, span: Span) -> Lit {
715 let (token, suffix) = node.to_lit_token();
716 Lit { node, token, suffix, span }
720 pub trait HasAttrs: Sized {
721 fn attrs(&self) -> &[ast::Attribute];
722 fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
725 impl<T: HasAttrs> HasAttrs for Spanned<T> {
726 fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
727 fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
728 self.node.visit_attrs(f);
732 impl HasAttrs for Vec<Attribute> {
733 fn attrs(&self) -> &[Attribute] {
736 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
741 impl HasAttrs for ThinVec<Attribute> {
742 fn attrs(&self) -> &[Attribute] {
745 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
746 visit_clobber(self, |this| {
747 let mut vec = this.into();
754 impl<T: HasAttrs + 'static> HasAttrs for P<T> {
755 fn attrs(&self) -> &[Attribute] {
758 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
759 (**self).visit_attrs(f);
763 impl HasAttrs for StmtKind {
764 fn attrs(&self) -> &[Attribute] {
766 StmtKind::Local(ref local) => local.attrs(),
767 StmtKind::Item(..) => &[],
768 StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
769 StmtKind::Mac(ref mac) => {
770 let (_, _, ref attrs) = **mac;
776 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
778 StmtKind::Local(local) => local.visit_attrs(f),
779 StmtKind::Item(..) => {}
780 StmtKind::Expr(expr) => expr.visit_attrs(f),
781 StmtKind::Semi(expr) => expr.visit_attrs(f),
782 StmtKind::Mac(mac) => {
783 let (_mac, _style, attrs) = mac.deref_mut();
784 attrs.visit_attrs(f);
790 impl HasAttrs for Stmt {
791 fn attrs(&self) -> &[ast::Attribute] {
795 fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
796 self.node.visit_attrs(f);
800 impl HasAttrs for GenericParam {
801 fn attrs(&self) -> &[ast::Attribute] {
805 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
806 self.attrs.visit_attrs(f);
810 macro_rules! derive_has_attrs {
811 ($($ty:path),*) => { $(
812 impl HasAttrs for $ty {
813 fn attrs(&self) -> &[Attribute] {
817 fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
818 self.attrs.visit_attrs(f);
825 Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
826 ast::Field, ast::FieldPat, ast::Variant_
829 pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
830 for raw_attr in attrs {
831 let mut parser = parse::new_parser_from_source_str(
833 FileName::cli_crate_attr_source_code(&raw_attr),
837 let start_span = parser.span;
838 let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted());
839 let end_span = parser.span;
840 if parser.token != token::Eof {
841 parse_sess.span_diagnostic
842 .span_err(start_span.to(end_span), "invalid crate attribute");
846 krate.attrs.push(Attribute {
848 style: AttrStyle::Inner,
851 is_sugared_doc: false,
852 span: start_span.to(end_span),