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, NestedMetaItemKind}
;
17 use crate::ast
::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam}
;
18 use crate::mut_visit
::visit_clobber
;
19 use crate::source_map
::{BytePos, Spanned, respan, 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
::Symbol
;
27 use crate::tokenstream
::{TokenStream, TokenTree, DelimSpan}
;
31 use syntax_pos
::{FileName, Span}
;
34 use std
::ops
::DerefMut
;
36 pub fn mark_used(attr
: &Attribute
) {
37 debug
!("Marking {:?} as used.", attr
);
38 GLOBALS
.with(|globals
| {
39 globals
.used_attrs
.lock().insert(attr
.id
);
43 pub fn is_used(attr
: &Attribute
) -> bool
{
44 GLOBALS
.with(|globals
| {
45 globals
.used_attrs
.lock().contains(attr
.id
)
49 pub fn mark_known(attr
: &Attribute
) {
50 debug
!("Marking {:?} as known.", attr
);
51 GLOBALS
.with(|globals
| {
52 globals
.known_attrs
.lock().insert(attr
.id
);
56 pub fn is_known(attr
: &Attribute
) -> bool
{
57 GLOBALS
.with(|globals
| {
58 globals
.known_attrs
.lock().contains(attr
.id
)
62 pub fn is_known_lint_tool(m_item
: Ident
) -> bool
{
63 ["clippy"].contains(&m_item
.as_str().as_ref())
67 /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
68 pub fn meta_item(&self) -> Option
<&MetaItem
> {
70 NestedMetaItemKind
::MetaItem(ref item
) => Some(item
),
75 /// Returns the Lit if self is a NestedMetaItemKind::Literal.
76 pub fn literal(&self) -> Option
<&Lit
> {
78 NestedMetaItemKind
::Literal(ref lit
) => Some(lit
),
83 /// Returns the Span for `self`.
84 pub fn span(&self) -> Span
{
88 /// Returns `true` if this list item is a MetaItem with a name of `name`.
89 pub fn check_name(&self, name
: &str) -> 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 ident_str(&self) -> Option
<&str> {
98 self.ident().map(|name
| name
.as_str().get())
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(&self, name
: &str) -> bool
{
160 let matches
= self.path
== name
;
167 /// For a single-segment attribute returns its name, otherwise returns `None`.
168 pub fn ident(&self) -> Option
<Ident
> {
169 if self.path
.segments
.len() == 1 {
170 Some(self.path
.segments
[0].ident
)
175 pub fn ident_str(&self) -> Option
<&str> {
176 self.ident().map(|name
| name
.as_str().get())
179 pub fn value_str(&self) -> Option
<Symbol
> {
180 self.meta().and_then(|meta
| meta
.value_str())
183 pub fn meta_item_list(&self) -> Option
<Vec
<NestedMetaItem
>> {
185 Some(MetaItem { node: MetaItemKind::List(list), .. }
) => Some(list
),
190 pub fn is_word(&self) -> bool
{
191 self.tokens
.is_empty()
194 pub fn span(&self) -> Span
{
198 pub fn is_meta_item_list(&self) -> bool
{
199 self.meta_item_list().is_some()
202 /// Indicates if the attribute is a Value String.
203 pub fn is_value_str(&self) -> bool
{
204 self.value_str().is_some()
209 /// For a single-segment meta-item returns its name, otherwise returns `None`.
210 pub fn ident(&self) -> Option
<Ident
> {
211 if self.ident
.segments
.len() == 1 {
212 Some(self.ident
.segments
[0].ident
)
217 pub fn ident_str(&self) -> Option
<&str> {
218 self.ident().map(|name
| name
.as_str().get())
221 // #[attribute(name = "value")]
223 pub fn name_value_literal(&self) -> Option
<&Lit
> {
225 MetaItemKind
::NameValue(v
) => Some(v
),
230 pub fn value_str(&self) -> Option
<Symbol
> {
232 MetaItemKind
::NameValue(ref v
) => {
234 LitKind
::Str(ref s
, _
) => Some(*s
),
242 pub fn meta_item_list(&self) -> Option
<&[NestedMetaItem
]> {
244 MetaItemKind
::List(ref l
) => Some(&l
[..]),
249 pub fn is_word(&self) -> bool
{
251 MetaItemKind
::Word
=> true,
256 pub fn span(&self) -> Span { self.span }
258 pub fn check_name(&self, name
: &str) -> 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 ident
: 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 ident
: 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 value
= respan(value
.span
, LitKind
::Str(value
.node
, ast
::StrStyle
::Cooked
));
356 mk_name_value_item(ident
.span
.to(value
.span
), ident
, value
)
359 pub fn mk_name_value_item(span
: Span
, ident
: Ident
, value
: ast
::Lit
) -> MetaItem
{
360 MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) }
363 pub fn mk_list_item(span
: Span
, ident
: Ident
, items
: Vec
<NestedMetaItem
>) -> MetaItem
{
364 MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::List(items) }
367 pub fn mk_word_item(ident
: Ident
) -> MetaItem
{
368 MetaItem { ident: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word }
371 pub fn mk_nested_word_item(ident
: Ident
) -> NestedMetaItem
{
372 respan(ident
.span
, NestedMetaItemKind
::MetaItem(mk_word_item(ident
)))
375 pub fn mk_attr_id() -> AttrId
{
376 use std
::sync
::atomic
::AtomicUsize
;
377 use std
::sync
::atomic
::Ordering
;
379 static NEXT_ATTR_ID
: AtomicUsize
= AtomicUsize
::new(0);
381 let id
= NEXT_ATTR_ID
.fetch_add(1, Ordering
::SeqCst
);
382 assert
!(id
!= ::std
::usize::MAX
);
386 /// Returns an inner attribute with the given value.
387 pub fn mk_attr_inner(span
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
388 mk_spanned_attr_inner(span
, id
, item
)
391 /// Returns an inner attribute with the given value and span.
392 pub fn mk_spanned_attr_inner(sp
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
395 style
: ast
::AttrStyle
::Inner
,
397 tokens
: item
.node
.tokens(item
.span
),
398 is_sugared_doc
: false,
403 /// Returns an outer attribute with the given value.
404 pub fn mk_attr_outer(span
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
405 mk_spanned_attr_outer(span
, id
, item
)
408 /// Returns an outer attribute with the given value and span.
409 pub fn mk_spanned_attr_outer(sp
: Span
, id
: AttrId
, item
: MetaItem
) -> Attribute
{
412 style
: ast
::AttrStyle
::Outer
,
414 tokens
: item
.node
.tokens(item
.span
),
415 is_sugared_doc
: false,
420 pub fn mk_sugared_doc_attr(id
: AttrId
, text
: Symbol
, span
: Span
) -> Attribute
{
421 let style
= doc_comment_style(&text
.as_str());
422 let lit
= respan(span
, LitKind
::Str(text
, ast
::StrStyle
::Cooked
));
426 path
: Path
::from_ident(Ident
::from_str("doc").with_span_pos(span
)),
427 tokens
: MetaItemKind
::NameValue(lit
).tokens(span
),
428 is_sugared_doc
: true,
433 pub fn list_contains_name(items
: &[NestedMetaItem
], name
: &str) -> bool
{
434 items
.iter().any(|item
| {
435 item
.check_name(name
)
439 pub fn contains_name(attrs
: &[Attribute
], name
: &str) -> bool
{
440 attrs
.iter().any(|item
| {
441 item
.check_name(name
)
445 pub fn find_by_name
<'a
>(attrs
: &'a
[Attribute
], name
: &str) -> Option
<&'a Attribute
> {
446 attrs
.iter().find(|attr
| attr
.check_name(name
))
449 pub fn filter_by_name
<'a
>(attrs
: &'a
[Attribute
], name
: &'a
str)
450 -> impl Iterator
<Item
= &'a Attribute
> {
451 attrs
.iter().filter(move |attr
| attr
.check_name(name
))
454 pub fn first_attr_value_str_by_name(attrs
: &[Attribute
], name
: &str) -> Option
<Symbol
> {
456 .find(|at
| at
.check_name(name
))
457 .and_then(|at
| at
.value_str())
461 fn tokens(&self) -> TokenStream
{
462 let mut idents
= vec
![];
463 let mut last_pos
= BytePos(0 as u32);
464 for (i
, segment
) in self.ident
.segments
.iter().enumerate() {
465 let is_first
= i
== 0;
467 let mod_sep_span
= Span
::new(last_pos
,
468 segment
.ident
.span
.lo(),
469 segment
.ident
.span
.ctxt());
470 idents
.push(TokenTree
::Token(mod_sep_span
, Token
::ModSep
).into());
472 idents
.push(TokenTree
::Token(segment
.ident
.span
,
473 Token
::from_ast_ident(segment
.ident
)).into());
474 last_pos
= segment
.ident
.span
.hi();
476 self.node
.tokens(self.span
).append_to_tree_and_joint_vec(&mut idents
);
477 TokenStream
::new(idents
)
480 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItem
>
481 where I
: Iterator
<Item
= TokenTree
>,
483 // FIXME: Share code with `parse_path`.
484 let ident
= match tokens
.next() {
485 Some(TokenTree
::Token(span
, token @ Token
::Ident(..))) |
486 Some(TokenTree
::Token(span
, token @ Token
::ModSep
)) => 'arm
: {
487 let mut segments
= if let Token
::Ident(ident
, _
) = token
{
488 if let Some(TokenTree
::Token(_
, Token
::ModSep
)) = tokens
.peek() {
490 vec
![PathSegment
::from_ident(ident
.with_span_pos(span
))]
492 break 'arm Path
::from_ident(ident
.with_span_pos(span
));
495 vec
![PathSegment
::path_root(span
)]
498 if let Some(TokenTree
::Token(span
,
499 Token
::Ident(ident
, _
))) = tokens
.next() {
500 segments
.push(PathSegment
::from_ident(ident
.with_span_pos(span
)));
504 if let Some(TokenTree
::Token(_
, Token
::ModSep
)) = tokens
.peek() {
510 let span
= span
.with_hi(segments
.last().unwrap().ident
.span
.hi());
511 Path { span, segments }
513 Some(TokenTree
::Token(_
, Token
::Interpolated(nt
))) => match *nt
{
514 token
::Nonterminal
::NtIdent(ident
, _
) => Path
::from_ident(ident
),
515 token
::Nonterminal
::NtMeta(ref meta
) => return Some(meta
.clone()),
516 token
::Nonterminal
::NtPath(ref path
) => path
.clone(),
521 let list_closing_paren_pos
= tokens
.peek().map(|tt
| tt
.span().hi());
522 let node
= MetaItemKind
::from_tokens(tokens
)?
;
523 let hi
= match node
{
524 MetaItemKind
::NameValue(ref lit
) => lit
.span
.hi(),
525 MetaItemKind
::List(..) => list_closing_paren_pos
.unwrap_or(ident
.span
.hi()),
526 _
=> ident
.span
.hi(),
528 let span
= ident
.span
.with_hi(hi
);
529 Some(MetaItem { ident, node, span }
)
534 pub fn tokens(&self, span
: Span
) -> TokenStream
{
536 MetaItemKind
::Word
=> TokenStream
::empty(),
537 MetaItemKind
::NameValue(ref lit
) => {
538 let mut vec
= vec
![TokenTree
::Token(span
, Token
::Eq
).into()];
539 lit
.tokens().append_to_tree_and_joint_vec(&mut vec
);
540 TokenStream
::new(vec
)
542 MetaItemKind
::List(ref list
) => {
543 let mut tokens
= Vec
::new();
544 for (i
, item
) in list
.iter().enumerate() {
546 tokens
.push(TokenTree
::Token(span
, Token
::Comma
).into());
548 item
.node
.tokens().append_to_tree_and_joint_vec(&mut tokens
);
550 TokenTree
::Delimited(
551 DelimSpan
::from_single(span
),
553 TokenStream
::new(tokens
).into(),
559 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<MetaItemKind
>
560 where I
: Iterator
<Item
= TokenTree
>,
562 let delimited
= match tokens
.peek().cloned() {
563 Some(TokenTree
::Token(_
, token
::Eq
)) => {
565 return if let Some(TokenTree
::Token(span
, token
)) = tokens
.next() {
566 LitKind
::from_token(token
)
567 .map(|lit
| MetaItemKind
::NameValue(Spanned { node: lit, span: span }
))
572 Some(TokenTree
::Delimited(_
, delim
, ref tts
)) if delim
== token
::Paren
=> {
576 _
=> return Some(MetaItemKind
::Word
),
579 let mut tokens
= delimited
.into_trees().peekable();
580 let mut result
= Vec
::new();
581 while let Some(..) = tokens
.peek() {
582 let item
= NestedMetaItemKind
::from_tokens(&mut tokens
)?
;
583 result
.push(respan(item
.span(), item
));
584 match tokens
.next() {
585 None
| Some(TokenTree
::Token(_
, Token
::Comma
)) => {}
589 Some(MetaItemKind
::List(result
))
593 impl NestedMetaItemKind
{
594 fn span(&self) -> Span
{
596 NestedMetaItemKind
::MetaItem(ref item
) => item
.span
,
597 NestedMetaItemKind
::Literal(ref lit
) => lit
.span
,
601 fn tokens(&self) -> TokenStream
{
603 NestedMetaItemKind
::MetaItem(ref item
) => item
.tokens(),
604 NestedMetaItemKind
::Literal(ref lit
) => lit
.tokens(),
608 fn from_tokens
<I
>(tokens
: &mut iter
::Peekable
<I
>) -> Option
<NestedMetaItemKind
>
609 where I
: Iterator
<Item
= TokenTree
>,
611 if let Some(TokenTree
::Token(span
, token
)) = tokens
.peek().cloned() {
612 if let Some(node
) = LitKind
::from_token(token
) {
614 return Some(NestedMetaItemKind
::Literal(respan(span
, node
)));
618 MetaItem
::from_tokens(tokens
).map(NestedMetaItemKind
::MetaItem
)
623 crate fn tokens(&self) -> TokenStream
{
624 TokenTree
::Token(self.span
, self.node
.token()).into()
629 fn token(&self) -> Token
{
633 LitKind
::Str(string
, ast
::StrStyle
::Cooked
) => {
634 let escaped
= string
.as_str().escape_default().to_string();
635 Token
::Literal(token
::Lit
::Str_(Symbol
::intern(&escaped
)), None
)
637 LitKind
::Str(string
, ast
::StrStyle
::Raw(n
)) => {
638 Token
::Literal(token
::Lit
::StrRaw(string
, n
), None
)
640 LitKind
::ByteStr(ref bytes
) => {
641 let string
= bytes
.iter().cloned().flat_map(ascii
::escape_default
)
642 .map(Into
::<char>::into
).collect
::<String
>();
643 Token
::Literal(token
::Lit
::ByteStr(Symbol
::intern(&string
)), None
)
645 LitKind
::Byte(byte
) => {
646 let string
: String
= ascii
::escape_default(byte
).map(Into
::<char>::into
).collect();
647 Token
::Literal(token
::Lit
::Byte(Symbol
::intern(&string
)), None
)
649 LitKind
::Char(ch
) => {
650 let string
: String
= ch
.escape_default().map(Into
::<char>::into
).collect();
651 Token
::Literal(token
::Lit
::Char(Symbol
::intern(&string
)), None
)
653 LitKind
::Int(n
, ty
) => {
654 let suffix
= match ty
{
655 ast
::LitIntType
::Unsigned(ty
) => Some(Symbol
::intern(ty
.ty_to_string())),
656 ast
::LitIntType
::Signed(ty
) => Some(Symbol
::intern(ty
.ty_to_string())),
657 ast
::LitIntType
::Unsuffixed
=> None
,
659 Token
::Literal(token
::Lit
::Integer(Symbol
::intern(&n
.to_string())), suffix
)
661 LitKind
::Float(symbol
, ty
) => {
662 Token
::Literal(token
::Lit
::Float(symbol
), Some(Symbol
::intern(ty
.ty_to_string())))
664 LitKind
::FloatUnsuffixed(symbol
) => Token
::Literal(token
::Lit
::Float(symbol
), None
),
665 LitKind
::Bool(value
) => Token
::Ident(Ident
::with_empty_ctxt(Symbol
::intern(if value
{
670 LitKind
::Err(val
) => Token
::Literal(token
::Lit
::Err(val
), None
),
674 fn from_token(token
: Token
) -> Option
<LitKind
> {
676 Token
::Ident(ident
, false) if ident
.name
== "true" => Some(LitKind
::Bool(true)),
677 Token
::Ident(ident
, false) if ident
.name
== "false" => Some(LitKind
::Bool(false)),
678 Token
::Interpolated(nt
) => match *nt
{
679 token
::NtExpr(ref v
) | token
::NtLiteral(ref v
) => match v
.node
{
680 ExprKind
::Lit(ref lit
) => Some(lit
.node
.clone()),
685 Token
::Literal(lit
, suf
) => {
686 let (suffix_illegal
, result
) = parse
::lit_token(lit
, suf
, None
);
687 if suffix_illegal
&& suf
.is_some() {
697 pub trait HasAttrs
: Sized
{
698 fn attrs(&self) -> &[ast
::Attribute
];
699 fn visit_attrs
<F
: FnOnce(&mut Vec
<ast
::Attribute
>)>(&mut self, f
: F
);
702 impl<T
: HasAttrs
> HasAttrs
for Spanned
<T
> {
703 fn attrs(&self) -> &[ast
::Attribute
] { self.node.attrs() }
704 fn visit_attrs
<F
: FnOnce(&mut Vec
<ast
::Attribute
>)>(&mut self, f
: F
) {
705 self.node
.visit_attrs(f
);
709 impl HasAttrs
for Vec
<Attribute
> {
710 fn attrs(&self) -> &[Attribute
] {
713 fn visit_attrs
<F
: FnOnce(&mut Vec
<Attribute
>)>(&mut self, f
: F
) {
718 impl HasAttrs
for ThinVec
<Attribute
> {
719 fn attrs(&self) -> &[Attribute
] {
722 fn visit_attrs
<F
: FnOnce(&mut Vec
<Attribute
>)>(&mut self, f
: F
) {
723 visit_clobber(self, |this
| {
724 let mut vec
= this
.into();
731 impl<T
: HasAttrs
+ '
static> HasAttrs
for P
<T
> {
732 fn attrs(&self) -> &[Attribute
] {
735 fn visit_attrs
<F
: FnOnce(&mut Vec
<Attribute
>)>(&mut self, f
: F
) {
736 (**self).visit_attrs(f
);
740 impl HasAttrs
for StmtKind
{
741 fn attrs(&self) -> &[Attribute
] {
743 StmtKind
::Local(ref local
) => local
.attrs(),
744 StmtKind
::Item(..) => &[],
745 StmtKind
::Expr(ref expr
) | StmtKind
::Semi(ref expr
) => expr
.attrs(),
746 StmtKind
::Mac(ref mac
) => {
747 let (_
, _
, ref attrs
) = **mac
;
753 fn visit_attrs
<F
: FnOnce(&mut Vec
<Attribute
>)>(&mut self, f
: F
) {
755 StmtKind
::Local(local
) => local
.visit_attrs(f
),
756 StmtKind
::Item(..) => {}
757 StmtKind
::Expr(expr
) => expr
.visit_attrs(f
),
758 StmtKind
::Semi(expr
) => expr
.visit_attrs(f
),
759 StmtKind
::Mac(mac
) => {
760 let (_mac
, _style
, attrs
) = mac
.deref_mut();
761 attrs
.visit_attrs(f
);
767 impl HasAttrs
for Stmt
{
768 fn attrs(&self) -> &[ast
::Attribute
] {
772 fn visit_attrs
<F
: FnOnce(&mut Vec
<ast
::Attribute
>)>(&mut self, f
: F
) {
773 self.node
.visit_attrs(f
);
777 impl HasAttrs
for GenericParam
{
778 fn attrs(&self) -> &[ast
::Attribute
] {
782 fn visit_attrs
<F
: FnOnce(&mut Vec
<Attribute
>)>(&mut self, f
: F
) {
783 self.attrs
.visit_attrs(f
);
787 macro_rules
! derive_has_attrs
{
788 ($
($ty
:path
),*) => { $
(
789 impl HasAttrs
for $ty
{
790 fn attrs(&self) -> &[Attribute
] {
794 fn visit_attrs
<F
: FnOnce(&mut Vec
<Attribute
>)>(&mut self, f
: F
) {
795 self.attrs
.visit_attrs(f
);
802 Item
, Expr
, Local
, ast
::ForeignItem
, ast
::StructField
, ast
::ImplItem
, ast
::TraitItem
, ast
::Arm
,
803 ast
::Field
, ast
::FieldPat
, ast
::Variant_
806 pub fn inject(mut krate
: ast
::Crate
, parse_sess
: &ParseSess
, attrs
: &[String
]) -> ast
::Crate
{
807 for raw_attr
in attrs
{
808 let mut parser
= parse
::new_parser_from_source_str(
810 FileName
::cli_crate_attr_source_code(&raw_attr
),
814 let start_span
= parser
.span
;
815 let (path
, tokens
) = panictry
!(parser
.parse_meta_item_unrestricted());
816 let end_span
= parser
.span
;
817 if parser
.token
!= token
::Eof
{
818 parse_sess
.span_diagnostic
819 .span_err(start_span
.to(end_span
), "invalid crate attribute");
823 krate
.attrs
.push(Attribute
{
825 style
: AttrStyle
::Inner
,
828 is_sugared_doc
: false,
829 span
: start_span
.to(end_span
),
836 // APIs used by clippy and resurrected for beta
838 pub fn name(&self) -> Name
{
839 self.path
.segments
.last().expect("empty path in attribute").ident
.name
843 pub fn name(&self) -> Name
{
844 self.ident
.segments
.last().expect("empty path in attribute").ident
.name
846 pub fn is_scoped(&self) -> Option
<Ident
> {
847 if self.ident
.segments
.len() > 1 {
848 Some(self.ident
.segments
[0].ident
)
854 impl NestedMetaItem
{
855 pub fn word(&self) -> Option
<&MetaItem
> {
856 self.meta_item().and_then(|meta_item
| if meta_item
.is_word() {