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