]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/attr/mod.rs
Auto merge of #58021 - ishitatsuyuki:57667-fix, r=RalfJung
[rust.git] / src / libsyntax / attr / mod.rs
1 //! Functions dealing with attributes and meta items
2
3 mod builtin;
4
5 pub use builtin::{
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,
9 };
10 pub use IntType::*;
11 pub use ReprAttr::*;
12 pub use StabilityLevel::*;
13
14 use crate::ast;
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};
24 use crate::ptr::P;
25 use crate::symbol::Symbol;
26 use crate::ThinVec;
27 use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
28 use crate::GLOBALS;
29
30 use log::debug;
31 use syntax_pos::{FileName, Span};
32
33 use std::iter;
34 use std::ops::DerefMut;
35
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);
40     });
41 }
42
43 pub fn is_used(attr: &Attribute) -> bool {
44     GLOBALS.with(|globals| {
45         globals.used_attrs.lock().contains(attr.id)
46     })
47 }
48
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);
53     });
54 }
55
56 pub fn is_known(attr: &Attribute) -> bool {
57     GLOBALS.with(|globals| {
58         globals.known_attrs.lock().contains(attr.id)
59     })
60 }
61
62 pub fn is_known_lint_tool(m_item: Ident) -> bool {
63     ["clippy"].contains(&m_item.as_str().as_ref())
64 }
65
66 impl NestedMetaItem {
67     /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
68     pub fn meta_item(&self) -> Option<&MetaItem> {
69         match self.node {
70             NestedMetaItemKind::MetaItem(ref item) => Some(item),
71             _ => None
72         }
73     }
74
75     /// Returns the Lit if self is a NestedMetaItemKind::Literal.
76     pub fn literal(&self) -> Option<&Lit> {
77         match self.node {
78             NestedMetaItemKind::Literal(ref lit) => Some(lit),
79             _ => None
80         }
81     }
82
83     /// Returns the Span for `self`.
84     pub fn span(&self) -> Span {
85         self.span
86     }
87
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))
91     }
92
93     /// Returns the name of the meta item, e.g., `foo` in `#[foo]`,
94     /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
95     pub fn name(&self) -> Option<Name> {
96         self.meta_item().and_then(|meta_item| Some(meta_item.name()))
97     }
98
99     /// Gets the string value if self is a MetaItem and the MetaItem is a
100     /// MetaItemKind::NameValue variant containing a string, otherwise None.
101     pub fn value_str(&self) -> Option<Symbol> {
102         self.meta_item().and_then(|meta_item| meta_item.value_str())
103     }
104
105     /// Returns a name and single literal value tuple of the MetaItem.
106     pub fn name_value_literal(&self) -> Option<(Name, &Lit)> {
107         self.meta_item().and_then(
108             |meta_item| meta_item.meta_item_list().and_then(
109                 |meta_item_list| {
110                     if meta_item_list.len() == 1 {
111                         let nested_item = &meta_item_list[0];
112                         if nested_item.is_literal() {
113                             Some((meta_item.name(), nested_item.literal().unwrap()))
114                         } else {
115                             None
116                         }
117                     }
118                     else {
119                         None
120                     }}))
121     }
122
123     /// Returns a MetaItem if self is a MetaItem with Kind Word.
124     pub fn word(&self) -> Option<&MetaItem> {
125         self.meta_item().and_then(|meta_item| if meta_item.is_word() {
126             Some(meta_item)
127         } else {
128             None
129         })
130     }
131
132     /// Gets a list of inner meta items from a list MetaItem type.
133     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
134         self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
135     }
136
137     /// Returns `true` if the variant is MetaItem.
138     pub fn is_meta_item(&self) -> bool {
139         self.meta_item().is_some()
140     }
141
142     /// Returns `true` if the variant is Literal.
143     pub fn is_literal(&self) -> bool {
144         self.literal().is_some()
145     }
146
147     /// Returns `true` if self is a MetaItem and the meta item is a word.
148     pub fn is_word(&self) -> bool {
149         self.word().is_some()
150     }
151
152     /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
153     pub fn is_value_str(&self) -> bool {
154         self.value_str().is_some()
155     }
156
157     /// Returns `true` if self is a MetaItem and the meta item is a list.
158     pub fn is_meta_item_list(&self) -> bool {
159         self.meta_item_list().is_some()
160     }
161 }
162
163 fn name_from_path(path: &Path) -> Name {
164     path.segments.last().expect("empty path in attribute").ident.name
165 }
166
167 impl Attribute {
168     /// Returns `true` if the attribute's path matches the argument. If it matches, then the
169     /// attribute is marked as used.
170     ///
171     /// To check the attribute name without marking it used, use the `path` field directly.
172     pub fn check_name(&self, name: &str) -> bool {
173         let matches = self.path == name;
174         if matches {
175             mark_used(self);
176         }
177         matches
178     }
179
180     /// Returns the **last** segment of the name of this attribute.
181     /// e.g., `foo` for `#[foo]`, `skip` for `#[rustfmt::skip]`.
182     pub fn name(&self) -> Name {
183         name_from_path(&self.path)
184     }
185
186     pub fn value_str(&self) -> Option<Symbol> {
187         self.meta().and_then(|meta| meta.value_str())
188     }
189
190     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
191         match self.meta() {
192             Some(MetaItem { node: MetaItemKind::List(list), .. }) => Some(list),
193             _ => None
194         }
195     }
196
197     pub fn is_word(&self) -> bool {
198         self.path.segments.len() == 1 && self.tokens.is_empty()
199     }
200
201     pub fn span(&self) -> Span {
202         self.span
203     }
204
205     pub fn is_meta_item_list(&self) -> bool {
206         self.meta_item_list().is_some()
207     }
208
209     /// Indicates if the attribute is a Value String.
210     pub fn is_value_str(&self) -> bool {
211         self.value_str().is_some()
212     }
213 }
214
215 impl MetaItem {
216     pub fn name(&self) -> Name {
217         name_from_path(&self.ident)
218     }
219
220     // #[attribute(name = "value")]
221     //             ^^^^^^^^^^^^^^
222     pub fn name_value_literal(&self) -> Option<&Lit> {
223         match &self.node {
224             MetaItemKind::NameValue(v) => Some(v),
225             _ => None,
226         }
227     }
228
229     pub fn value_str(&self) -> Option<Symbol> {
230         match self.node {
231             MetaItemKind::NameValue(ref v) => {
232                 match v.node {
233                     LitKind::Str(ref s, _) => Some(*s),
234                     _ => None,
235                 }
236             },
237             _ => None
238         }
239     }
240
241     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
242         match self.node {
243             MetaItemKind::List(ref l) => Some(&l[..]),
244             _ => None
245         }
246     }
247
248     pub fn is_word(&self) -> bool {
249         match self.node {
250             MetaItemKind::Word => true,
251             _ => false,
252         }
253     }
254
255     pub fn span(&self) -> Span { self.span }
256
257     pub fn check_name(&self, name: &str) -> bool {
258         self.name() == name
259     }
260
261     pub fn is_value_str(&self) -> bool {
262         self.value_str().is_some()
263     }
264
265     pub fn is_meta_item_list(&self) -> bool {
266         self.meta_item_list().is_some()
267     }
268
269     pub fn is_scoped(&self) -> Option<Ident> {
270         if self.ident.segments.len() > 1 {
271             Some(self.ident.segments[0].ident)
272         } else {
273             None
274         }
275     }
276 }
277
278 impl Attribute {
279     /// Extracts the MetaItem from inside this Attribute.
280     pub fn meta(&self) -> Option<MetaItem> {
281         let mut tokens = self.tokens.trees().peekable();
282         Some(MetaItem {
283             ident: self.path.clone(),
284             node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) {
285                 if tokens.peek().is_some() {
286                     return None;
287                 }
288                 node
289             } else {
290                 return None;
291             },
292             span: self.span,
293         })
294     }
295
296     pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
297         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
298     {
299         let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
300         let result = f(&mut parser)?;
301         if parser.token != token::Eof {
302             parser.unexpected()?;
303         }
304         Ok(result)
305     }
306
307     pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec<T>>
308         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
309     {
310         if self.tokens.is_empty() {
311             return Ok(Vec::new());
312         }
313         self.parse(sess, |parser| {
314             parser.expect(&token::OpenDelim(token::Paren))?;
315             let mut list = Vec::new();
316             while !parser.eat(&token::CloseDelim(token::Paren)) {
317                 list.push(f(parser)?);
318                 if !parser.eat(&token::Comma) {
319                    parser.expect(&token::CloseDelim(token::Paren))?;
320                     break
321                 }
322             }
323             Ok(list)
324         })
325     }
326
327     pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
328         Ok(MetaItem {
329             ident: self.path.clone(),
330             node: self.parse(sess, |parser| parser.parse_meta_item_kind())?,
331             span: self.span,
332         })
333     }
334
335     /// Converts self to a normal #[doc="foo"] comment, if it is a
336     /// comment like `///` or `/** */`. (Returns self unchanged for
337     /// non-sugared doc attributes.)
338     pub fn with_desugared_doc<T, F>(&self, f: F) -> T where
339         F: FnOnce(&Attribute) -> T,
340     {
341         if self.is_sugared_doc {
342             let comment = self.value_str().unwrap();
343             let meta = mk_name_value_item_str(
344                 Ident::from_str("doc"),
345                 dummy_spanned(Symbol::intern(&strip_doc_comment_decoration(&comment.as_str()))));
346             let mut attr = if self.style == ast::AttrStyle::Outer {
347                 mk_attr_outer(self.span, self.id, meta)
348             } else {
349                 mk_attr_inner(self.span, self.id, meta)
350             };
351             attr.is_sugared_doc = true;
352             f(&attr)
353         } else {
354             f(self)
355         }
356     }
357 }
358
359 /* Constructors */
360
361 pub fn mk_name_value_item_str(ident: Ident, value: Spanned<Symbol>) -> MetaItem {
362     let value = respan(value.span, LitKind::Str(value.node, ast::StrStyle::Cooked));
363     mk_name_value_item(ident.span.to(value.span), ident, value)
364 }
365
366 pub fn mk_name_value_item(span: Span, ident: Ident, value: ast::Lit) -> MetaItem {
367     MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) }
368 }
369
370 pub fn mk_list_item(span: Span, ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
371     MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::List(items) }
372 }
373
374 pub fn mk_word_item(ident: Ident) -> MetaItem {
375     MetaItem { ident: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word }
376 }
377
378 pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
379     respan(ident.span, NestedMetaItemKind::MetaItem(mk_word_item(ident)))
380 }
381
382 pub fn mk_attr_id() -> AttrId {
383     use std::sync::atomic::AtomicUsize;
384     use std::sync::atomic::Ordering;
385
386     static NEXT_ATTR_ID: AtomicUsize = AtomicUsize::new(0);
387
388     let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
389     assert!(id != ::std::usize::MAX);
390     AttrId(id)
391 }
392
393 /// Returns an inner attribute with the given value.
394 pub fn mk_attr_inner(span: Span, id: AttrId, item: MetaItem) -> Attribute {
395     mk_spanned_attr_inner(span, id, item)
396 }
397
398 /// Returns an inner attribute with the given value and span.
399 pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute {
400     Attribute {
401         id,
402         style: ast::AttrStyle::Inner,
403         path: item.ident,
404         tokens: item.node.tokens(item.span),
405         is_sugared_doc: false,
406         span: sp,
407     }
408 }
409
410 /// Returns an outer attribute with the given value.
411 pub fn mk_attr_outer(span: Span, id: AttrId, item: MetaItem) -> Attribute {
412     mk_spanned_attr_outer(span, id, item)
413 }
414
415 /// Returns an outer attribute with the given value and span.
416 pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute {
417     Attribute {
418         id,
419         style: ast::AttrStyle::Outer,
420         path: item.ident,
421         tokens: item.node.tokens(item.span),
422         is_sugared_doc: false,
423         span: sp,
424     }
425 }
426
427 pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute {
428     let style = doc_comment_style(&text.as_str());
429     let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked));
430     Attribute {
431         id,
432         style,
433         path: Path::from_ident(Ident::from_str("doc").with_span_pos(span)),
434         tokens: MetaItemKind::NameValue(lit).tokens(span),
435         is_sugared_doc: true,
436         span,
437     }
438 }
439
440 pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool {
441     items.iter().any(|item| {
442         item.check_name(name)
443     })
444 }
445
446 pub fn contains_name(attrs: &[Attribute], name: &str) -> bool {
447     attrs.iter().any(|item| {
448         item.check_name(name)
449     })
450 }
451
452 pub fn find_by_name<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> {
453     attrs.iter().find(|attr| attr.check_name(name))
454 }
455
456 pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: &'a str)
457     -> impl Iterator<Item = &'a Attribute> {
458     attrs.iter().filter(move |attr| attr.check_name(name))
459 }
460
461 pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<Symbol> {
462     attrs.iter()
463         .find(|at| at.check_name(name))
464         .and_then(|at| at.value_str())
465 }
466
467 impl MetaItem {
468     fn tokens(&self) -> TokenStream {
469         let mut idents = vec![];
470         let mut last_pos = BytePos(0 as u32);
471         for (i, segment) in self.ident.segments.iter().enumerate() {
472             let is_first = i == 0;
473             if !is_first {
474                 let mod_sep_span = Span::new(last_pos,
475                                              segment.ident.span.lo(),
476                                              segment.ident.span.ctxt());
477                 idents.push(TokenTree::Token(mod_sep_span, Token::ModSep).into());
478             }
479             idents.push(TokenTree::Token(segment.ident.span,
480                                          Token::from_ast_ident(segment.ident)).into());
481             last_pos = segment.ident.span.hi();
482         }
483         self.node.tokens(self.span).append_to_tree_and_joint_vec(&mut idents);
484         TokenStream::new(idents)
485     }
486
487     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
488         where I: Iterator<Item = TokenTree>,
489     {
490         // FIXME: Share code with `parse_path`.
491         let ident = match tokens.next() {
492             Some(TokenTree::Token(span, token @ Token::Ident(..))) |
493             Some(TokenTree::Token(span, token @ Token::ModSep)) => 'arm: {
494                 let mut segments = if let Token::Ident(ident, _) = token {
495                     if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() {
496                         tokens.next();
497                         vec![PathSegment::from_ident(ident.with_span_pos(span))]
498                     } else {
499                         break 'arm Path::from_ident(ident.with_span_pos(span));
500                     }
501                 } else {
502                     vec![PathSegment::path_root(span)]
503                 };
504                 loop {
505                     if let Some(TokenTree::Token(span,
506                                                     Token::Ident(ident, _))) = tokens.next() {
507                         segments.push(PathSegment::from_ident(ident.with_span_pos(span)));
508                     } else {
509                         return None;
510                     }
511                     if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() {
512                         tokens.next();
513                     } else {
514                         break;
515                     }
516                 }
517                 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
518                 Path { span, segments }
519             }
520             Some(TokenTree::Token(_, Token::Interpolated(nt))) => match *nt {
521                 token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
522                 token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
523                 token::Nonterminal::NtPath(ref path) => path.clone(),
524                 _ => return None,
525             },
526             _ => return None,
527         };
528         let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
529         let node = MetaItemKind::from_tokens(tokens)?;
530         let hi = match node {
531             MetaItemKind::NameValue(ref lit) => lit.span.hi(),
532             MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(ident.span.hi()),
533             _ => ident.span.hi(),
534         };
535         let span = ident.span.with_hi(hi);
536         Some(MetaItem { ident, node, span })
537     }
538 }
539
540 impl MetaItemKind {
541     pub fn tokens(&self, span: Span) -> TokenStream {
542         match *self {
543             MetaItemKind::Word => TokenStream::empty(),
544             MetaItemKind::NameValue(ref lit) => {
545                 let mut vec = vec![TokenTree::Token(span, Token::Eq).into()];
546                 lit.tokens().append_to_tree_and_joint_vec(&mut vec);
547                 TokenStream::new(vec)
548             }
549             MetaItemKind::List(ref list) => {
550                 let mut tokens = Vec::new();
551                 for (i, item) in list.iter().enumerate() {
552                     if i > 0 {
553                         tokens.push(TokenTree::Token(span, Token::Comma).into());
554                     }
555                     item.node.tokens().append_to_tree_and_joint_vec(&mut tokens);
556                 }
557                 TokenTree::Delimited(
558                     DelimSpan::from_single(span),
559                     token::Paren,
560                     TokenStream::new(tokens).into(),
561                 ).into()
562             }
563         }
564     }
565
566     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind>
567         where I: Iterator<Item = TokenTree>,
568     {
569         let delimited = match tokens.peek().cloned() {
570             Some(TokenTree::Token(_, token::Eq)) => {
571                 tokens.next();
572                 return if let Some(TokenTree::Token(span, token)) = tokens.next() {
573                     LitKind::from_token(token)
574                         .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span }))
575                 } else {
576                     None
577                 };
578             }
579             Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => {
580                 tokens.next();
581                 tts.clone()
582             }
583             _ => return Some(MetaItemKind::Word),
584         };
585
586         let mut tokens = delimited.into_trees().peekable();
587         let mut result = Vec::new();
588         while let Some(..) = tokens.peek() {
589             let item = NestedMetaItemKind::from_tokens(&mut tokens)?;
590             result.push(respan(item.span(), item));
591             match tokens.next() {
592                 None | Some(TokenTree::Token(_, Token::Comma)) => {}
593                 _ => return None,
594             }
595         }
596         Some(MetaItemKind::List(result))
597     }
598 }
599
600 impl NestedMetaItemKind {
601     fn span(&self) -> Span {
602         match *self {
603             NestedMetaItemKind::MetaItem(ref item) => item.span,
604             NestedMetaItemKind::Literal(ref lit) => lit.span,
605         }
606     }
607
608     fn tokens(&self) -> TokenStream {
609         match *self {
610             NestedMetaItemKind::MetaItem(ref item) => item.tokens(),
611             NestedMetaItemKind::Literal(ref lit) => lit.tokens(),
612         }
613     }
614
615     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItemKind>
616         where I: Iterator<Item = TokenTree>,
617     {
618         if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() {
619             if let Some(node) = LitKind::from_token(token) {
620                 tokens.next();
621                 return Some(NestedMetaItemKind::Literal(respan(span, node)));
622             }
623         }
624
625         MetaItem::from_tokens(tokens).map(NestedMetaItemKind::MetaItem)
626     }
627 }
628
629 impl Lit {
630     crate fn tokens(&self) -> TokenStream {
631         TokenTree::Token(self.span, self.node.token()).into()
632     }
633 }
634
635 impl LitKind {
636     fn token(&self) -> Token {
637         use std::ascii;
638
639         match *self {
640             LitKind::Str(string, ast::StrStyle::Cooked) => {
641                 let escaped = string.as_str().escape_default().to_string();
642                 Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None)
643             }
644             LitKind::Str(string, ast::StrStyle::Raw(n)) => {
645                 Token::Literal(token::Lit::StrRaw(string, n), None)
646             }
647             LitKind::ByteStr(ref bytes) => {
648                 let string = bytes.iter().cloned().flat_map(ascii::escape_default)
649                     .map(Into::<char>::into).collect::<String>();
650                 Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None)
651             }
652             LitKind::Byte(byte) => {
653                 let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
654                 Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None)
655             }
656             LitKind::Char(ch) => {
657                 let string: String = ch.escape_default().map(Into::<char>::into).collect();
658                 Token::Literal(token::Lit::Char(Symbol::intern(&string)), None)
659             }
660             LitKind::Int(n, ty) => {
661                 let suffix = match ty {
662                     ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())),
663                     ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())),
664                     ast::LitIntType::Unsuffixed => None,
665                 };
666                 Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix)
667             }
668             LitKind::Float(symbol, ty) => {
669                 Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string())))
670             }
671             LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None),
672             LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(if value {
673                 "true"
674             } else {
675                 "false"
676             })), false),
677             LitKind::Err(val) => Token::Literal(token::Lit::Err(val), None),
678         }
679     }
680
681     fn from_token(token: Token) -> Option<LitKind> {
682         match token {
683             Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)),
684             Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)),
685             Token::Interpolated(nt) => match *nt {
686                 token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
687                     ExprKind::Lit(ref lit) => Some(lit.node.clone()),
688                     _ => None,
689                 },
690                 _ => None,
691             },
692             Token::Literal(lit, suf) => {
693                 let (suffix_illegal, result) = parse::lit_token(lit, suf, None);
694                 if suffix_illegal && suf.is_some() {
695                     return None;
696                 }
697                 result
698             }
699             _ => None,
700         }
701     }
702 }
703
704 pub trait HasAttrs: Sized {
705     fn attrs(&self) -> &[ast::Attribute];
706     fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
707 }
708
709 impl<T: HasAttrs> HasAttrs for Spanned<T> {
710     fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
711     fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
712         self.node.visit_attrs(f);
713     }
714 }
715
716 impl HasAttrs for Vec<Attribute> {
717     fn attrs(&self) -> &[Attribute] {
718         self
719     }
720     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
721         f(self)
722     }
723 }
724
725 impl HasAttrs for ThinVec<Attribute> {
726     fn attrs(&self) -> &[Attribute] {
727         self
728     }
729     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
730         visit_clobber(self, |this| {
731             let mut vec = this.into();
732             f(&mut vec);
733             vec.into()
734         });
735     }
736 }
737
738 impl<T: HasAttrs + 'static> HasAttrs for P<T> {
739     fn attrs(&self) -> &[Attribute] {
740         (**self).attrs()
741     }
742     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
743         (**self).visit_attrs(f);
744     }
745 }
746
747 impl HasAttrs for StmtKind {
748     fn attrs(&self) -> &[Attribute] {
749         match *self {
750             StmtKind::Local(ref local) => local.attrs(),
751             StmtKind::Item(..) => &[],
752             StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
753             StmtKind::Mac(ref mac) => {
754                 let (_, _, ref attrs) = **mac;
755                 attrs.attrs()
756             }
757         }
758     }
759
760     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
761         match self {
762             StmtKind::Local(local) => local.visit_attrs(f),
763             StmtKind::Item(..) => {}
764             StmtKind::Expr(expr) => expr.visit_attrs(f),
765             StmtKind::Semi(expr) => expr.visit_attrs(f),
766             StmtKind::Mac(mac) => {
767                 let (_mac, _style, attrs) = mac.deref_mut();
768                 attrs.visit_attrs(f);
769             }
770         }
771     }
772 }
773
774 impl HasAttrs for Stmt {
775     fn attrs(&self) -> &[ast::Attribute] {
776         self.node.attrs()
777     }
778
779     fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
780         self.node.visit_attrs(f);
781     }
782 }
783
784 impl HasAttrs for GenericParam {
785     fn attrs(&self) -> &[ast::Attribute] {
786         &self.attrs
787     }
788
789     fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
790         self.attrs.visit_attrs(f);
791     }
792 }
793
794 macro_rules! derive_has_attrs {
795     ($($ty:path),*) => { $(
796         impl HasAttrs for $ty {
797             fn attrs(&self) -> &[Attribute] {
798                 &self.attrs
799             }
800
801             fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
802                 self.attrs.visit_attrs(f);
803             }
804         }
805     )* }
806 }
807
808 derive_has_attrs! {
809     Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
810     ast::Field, ast::FieldPat, ast::Variant_
811 }
812
813 pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
814     for raw_attr in attrs {
815         let mut parser = parse::new_parser_from_source_str(
816             parse_sess,
817             FileName::cli_crate_attr_source_code(&raw_attr),
818             raw_attr.clone(),
819         );
820
821         let start_span = parser.span;
822         let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted());
823         let end_span = parser.span;
824         if parser.token != token::Eof {
825             parse_sess.span_diagnostic
826                 .span_err(start_span.to(end_span), "invalid crate attribute");
827             continue;
828         }
829
830         krate.attrs.push(Attribute {
831             id: mk_attr_id(),
832             style: AttrStyle::Inner,
833             path,
834             tokens,
835             is_sugared_doc: false,
836             span: start_span.to(end_span),
837         });
838     }
839
840     krate
841 }