blob: 41715531f7fe37dcc59dbddd1147360ec5233b0d [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -07002use delimited::Delimited;
David Tolnayb79ee962016-09-04 09:39:20 -07003
David Tolnay4a51dc72016-10-01 00:40:31 -07004use std::iter;
5
David Tolnay9c76bcb2017-12-26 23:14:59 -05006use proc_macro2::{Delimiter, TokenNode, TokenTree, Spacing};
7
8#[cfg(feature = "extra-traits")]
9use std::hash::{Hash, Hasher};
10#[cfg(feature = "extra-traits")]
11use mac::SliceTokenTreeHelper;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070012
Alex Crichton62a0a592017-05-22 13:58:53 -070013ast_struct! {
14 /// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
David Tolnay9c76bcb2017-12-26 23:14:59 -050015 pub struct Attribute #manual_extra_traits {
Alex Crichton62a0a592017-05-22 13:58:53 -070016 pub style: AttrStyle,
David Tolnayf8db7ba2017-11-11 22:52:16 -080017 pub pound_token: Token![#],
David Tolnay32954ef2017-12-26 22:43:16 -050018 pub bracket_token: token::Bracket,
Arnavion44d2bf32017-04-19 02:47:55 -070019
Alex Crichton62a0a592017-05-22 13:58:53 -070020 /// The path of the attribute.
21 ///
22 /// E.g. `derive` in `#[derive(Copy)]`
23 /// E.g. `crate::precondition` in `#[crate::precondition x < 5]`
24 pub path: Path,
Arnavion44d2bf32017-04-19 02:47:55 -070025
Alex Crichton62a0a592017-05-22 13:58:53 -070026 /// Any tokens after the path.
27 ///
28 /// E.g. `( Copy )` in `#[derive(Copy)]`
29 /// E.g. `x < 5` in `#[crate::precondition x < 5]`
30 pub tts: Vec<TokenTree>,
Arnavion44d2bf32017-04-19 02:47:55 -070031
Alex Crichton62a0a592017-05-22 13:58:53 -070032 pub is_sugared_doc: bool,
33 }
David Tolnayb79ee962016-09-04 09:39:20 -070034}
35
David Tolnay9c76bcb2017-12-26 23:14:59 -050036#[cfg(feature = "extra-traits")]
37impl Eq for Attribute {}
38
39#[cfg(feature = "extra-traits")]
40impl PartialEq for Attribute {
41 fn eq(&self, other: &Self) -> bool {
42 self.style == other.style
43 && self.pound_token == other.pound_token
44 && self.bracket_token == other.bracket_token
45 && self.path == other.path
46 && SliceTokenTreeHelper(&self.tts) == SliceTokenTreeHelper(&other.tts)
47 && self.is_sugared_doc == other.is_sugared_doc
48 }
49}
50
51#[cfg(feature = "extra-traits")]
52impl Hash for Attribute {
53 fn hash<H>(&self, state: &mut H)
54 where H: Hasher
55 {
56 self.style.hash(state);
57 self.pound_token.hash(state);
58 self.bracket_token.hash(state);
59 self.path.hash(state);
60 SliceTokenTreeHelper(&self.tts).hash(state);
61 self.is_sugared_doc.hash(state);
62 }
63}
64
David Tolnay02d77cc2016-10-02 09:52:08 -070065impl Attribute {
Arnavion44d2bf32017-04-19 02:47:55 -070066 /// Parses the tokens after the path as a [`MetaItem`](enum.MetaItem.html) if possible.
Arnavionbf395bf2017-04-15 15:35:22 -070067 pub fn meta_item(&self) -> Option<MetaItem> {
Arnavion95f8a7a2017-04-19 03:29:56 -070068 let name = if self.path.segments.len() == 1 {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070069 &self.path.segments.get(0).item().ident
Arnavion95f8a7a2017-04-19 03:29:56 -070070 } else {
71 return None;
72 };
73
Arnavionbf395bf2017-04-15 15:35:22 -070074 if self.tts.is_empty() {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050075 return Some(MetaItem::Term(*name));
Arnavionbf395bf2017-04-15 15:35:22 -070076 }
77
78 if self.tts.len() == 1 {
David Tolnay9c76bcb2017-12-26 23:14:59 -050079 if let TokenNode::Group(Delimiter::Parenthesis, ref ts) = self.tts[0].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070080 let tokens = ts.clone().into_iter().collect::<Vec<_>>();
81 if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(&tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -070082 return Some(MetaItem::List(MetaItemList {
David Tolnay9c76bcb2017-12-26 23:14:59 -050083 paren_token: token::Paren(self.tts[0].span),
David Tolnaybb4ca9f2017-12-26 12:28:58 -050084 ident: *name,
Alex Crichton62a0a592017-05-22 13:58:53 -070085 nested: nested_meta_items,
86 }));
Arnavionbf395bf2017-04-15 15:35:22 -070087 }
88 }
89 }
90
91 if self.tts.len() == 2 {
David Tolnay9c76bcb2017-12-26 23:14:59 -050092 if let TokenNode::Op('=', Spacing::Alone) = self.tts[0].kind {
93 if let TokenNode::Literal(ref lit) = self.tts[1].kind {
Alex Crichton62a0a592017-05-22 13:58:53 -070094 return Some(MetaItem::NameValue(MetaNameValue {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050095 ident: *name,
David Tolnay9c76bcb2017-12-26 23:14:59 -050096 eq_token: Token![=]([self.tts[0].span]),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070097 lit: Lit {
98 value: LitKind::Other(lit.clone()),
David Tolnay9c76bcb2017-12-26 23:14:59 -050099 span: self.tts[1].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700100 },
Alex Crichton62a0a592017-05-22 13:58:53 -0700101 }));
Arnavionbf395bf2017-04-15 15:35:22 -0700102 }
Arnavionbf395bf2017-04-15 15:35:22 -0700103 }
104 }
105
106 None
David Tolnay02d77cc2016-10-02 09:52:08 -0700107 }
108}
109
David Tolnay9c76bcb2017-12-26 23:14:59 -0500110fn nested_meta_item_from_tokens(tts: &[TokenTree])
111 -> Option<(NestedMetaItem, &[TokenTree])>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700112{
113 assert!(!tts.is_empty());
114
115 match tts[0].kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700116 TokenNode::Literal(ref lit) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700117 let lit = Lit {
118 value: LitKind::Other(lit.clone()),
David Tolnay98942562017-12-26 21:24:35 -0500119 span: tts[0].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700120 };
121 Some((NestedMetaItem::Literal(lit), &tts[1..]))
122 }
123
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700124 TokenNode::Term(sym) => {
David Tolnay98942562017-12-26 21:24:35 -0500125 let ident = Ident::new(sym, tts[0].span);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700126 if tts.len() >= 3 {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700127 if let TokenNode::Op('=', Spacing::Alone) = tts[1].kind {
128 if let TokenNode::Literal(ref lit) = tts[2].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700129 let pair = MetaNameValue {
David Tolnay98942562017-12-26 21:24:35 -0500130 ident: Ident::new(sym, tts[0].span),
131 eq_token: Token![=]([tts[1].span]),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700132 lit: Lit {
133 value: LitKind::Other(lit.clone()),
David Tolnay98942562017-12-26 21:24:35 -0500134 span: tts[2].span,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700135 },
136 };
137 return Some((MetaItem::NameValue(pair).into(), &tts[3..]));
138 }
139 }
140 }
141
142 if tts.len() >= 2 {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700143 if let TokenNode::Group(Delimiter::Parenthesis, ref inner_tts) = tts[1].kind {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700144 let inner_tts = inner_tts.clone().into_iter().collect::<Vec<_>>();
145 return match list_of_nested_meta_items_from_tokens(&inner_tts) {
146 Some(nested_meta_items) => {
147 let list = MetaItemList {
148 ident: ident,
David Tolnay32954ef2017-12-26 22:43:16 -0500149 paren_token: token::Paren(tts[1].span),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700150 nested: nested_meta_items,
151 };
152 Some((MetaItem::List(list).into(), &tts[2..]))
153 }
154
155 None => None
156 };
157 }
158 }
159
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700160 Some((MetaItem::Term(ident).into(), &tts[1..]))
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700161 }
162
163 _ => None
164 }
165}
166
David Tolnay9c76bcb2017-12-26 23:14:59 -0500167fn list_of_nested_meta_items_from_tokens(mut tts: &[TokenTree])
David Tolnayf8db7ba2017-11-11 22:52:16 -0800168 -> Option<Delimited<NestedMetaItem, Token![,]>>
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700169{
170 let mut delimited = Delimited::new();
171 let mut first = true;
172
173 while !tts.is_empty() {
174 let prev_comma = if first {
175 first = false;
176 None
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700177 } else if let TokenNode::Op(',', Spacing::Alone) = tts[0].kind {
David Tolnay98942562017-12-26 21:24:35 -0500178 let tok = Token![,]([tts[0].span]);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700179 tts = &tts[1..];
180 if tts.is_empty() {
181 break
182 }
183 Some(tok)
184 } else {
185 return None
186 };
187 let (nested, rest) = match nested_meta_item_from_tokens(tts) {
188 Some(pair) => pair,
189 None => return None,
190 };
191 match prev_comma {
192 Some(comma) => delimited.push_next(nested, comma),
193 None => delimited.push_first(nested),
194 }
195 tts = rest;
196 }
197
198 Some(delimited)
199}
200
201
Alex Crichton62a0a592017-05-22 13:58:53 -0700202ast_enum! {
203 /// Distinguishes between Attributes that decorate items and Attributes that
204 /// are contained as statements within items. These two cases need to be
205 /// distinguished for pretty-printing.
Alex Crichton2e0229c2017-05-23 09:34:50 -0700206 #[cfg_attr(feature = "clone-impls", derive(Copy))]
Alex Crichton62a0a592017-05-22 13:58:53 -0700207 pub enum AttrStyle {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700208 /// Attribute of the form `#[...]`.
Alex Crichton62a0a592017-05-22 13:58:53 -0700209 Outer,
Clar Charrd22b5702017-03-10 15:24:56 -0500210
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700211 /// Attribute of the form `#![...]`.
David Tolnayf8db7ba2017-11-11 22:52:16 -0800212 Inner(Token![!]),
Alex Crichton62a0a592017-05-22 13:58:53 -0700213 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700214}
215
Alex Crichton62a0a592017-05-22 13:58:53 -0700216ast_enum_of_structs! {
217 /// A compile-time attribute item.
David Tolnayb79ee962016-09-04 09:39:20 -0700218 ///
Alex Crichton62a0a592017-05-22 13:58:53 -0700219 /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
220 pub enum MetaItem {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700221 /// Term meta item.
Alex Crichton62a0a592017-05-22 13:58:53 -0700222 ///
223 /// E.g. `test` as in `#[test]`
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700224 pub Term(Ident),
Clar Charrd22b5702017-03-10 15:24:56 -0500225
Alex Crichton62a0a592017-05-22 13:58:53 -0700226 /// List meta item.
227 ///
228 /// E.g. `derive(..)` as in `#[derive(..)]`
229 pub List(MetaItemList {
230 /// Name of this attribute.
231 ///
232 /// E.g. `derive` in `#[derive(..)]`
233 pub ident: Ident,
Clar Charrd22b5702017-03-10 15:24:56 -0500234
David Tolnay32954ef2017-12-26 22:43:16 -0500235 pub paren_token: token::Paren,
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700236
Alex Crichton62a0a592017-05-22 13:58:53 -0700237 /// Arguments to this attribute
238 ///
239 /// E.g. `..` in `#[derive(..)]`
David Tolnayf8db7ba2017-11-11 22:52:16 -0800240 pub nested: Delimited<NestedMetaItem, Token![,]>,
Alex Crichton62a0a592017-05-22 13:58:53 -0700241 }),
242
243 /// Name-value meta item.
244 ///
245 /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
246 pub NameValue(MetaNameValue {
247 /// Name of this attribute.
248 ///
249 /// E.g. `feature` in `#[feature = "foo"]`
250 pub ident: Ident,
251
David Tolnayf8db7ba2017-11-11 22:52:16 -0800252 pub eq_token: Token![=],
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700253
Alex Crichton62a0a592017-05-22 13:58:53 -0700254 /// Arguments to this attribute
255 ///
256 /// E.g. `"foo"` in `#[feature = "foo"]`
257 pub lit: Lit,
258 }),
259 }
Arnavion95f8a7a2017-04-19 03:29:56 -0700260}
261
262impl MetaItem {
263 /// Name of the item.
264 ///
265 /// E.g. `test` as in `#[test]`, `derive` as in `#[derive(..)]`, and
266 /// `feature` as in `#[feature = "foo"]`.
267 pub fn name(&self) -> &str {
268 match *self {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700269 MetaItem::Term(ref name) => name.as_ref(),
Alex Crichton62a0a592017-05-22 13:58:53 -0700270 MetaItem::NameValue(ref pair) => pair.ident.as_ref(),
271 MetaItem::List(ref list) => list.ident.as_ref(),
Arnavion95f8a7a2017-04-19 03:29:56 -0700272 }
273 }
David Tolnay8e661e22016-09-27 00:00:04 -0700274}
275
Alex Crichton62a0a592017-05-22 13:58:53 -0700276ast_enum_of_structs! {
277 /// Possible values inside of compile-time attribute lists.
David Tolnayb7fa2b62016-10-30 10:50:47 -0700278 ///
Alex Crichton62a0a592017-05-22 13:58:53 -0700279 /// E.g. the '..' in `#[name(..)]`.
280 pub enum NestedMetaItem {
281 /// A full `MetaItem`.
282 ///
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700283 /// E.g. `Copy` in `#[derive(Copy)]` would be a `MetaItem::Term(Ident::from("Copy"))`.
Alex Crichton62a0a592017-05-22 13:58:53 -0700284 pub MetaItem(MetaItem),
Clar Charrd22b5702017-03-10 15:24:56 -0500285
Alex Crichton62a0a592017-05-22 13:58:53 -0700286 /// A Rust literal.
287 ///
288 /// E.g. `"name"` in `#[rename("name")]`.
289 pub Literal(Lit),
290 }
David Tolnayb7fa2b62016-10-30 10:50:47 -0700291}
292
David Tolnay4a51dc72016-10-01 00:40:31 -0700293pub trait FilterAttrs<'a> {
294 type Ret: Iterator<Item = &'a Attribute>;
295
296 fn outer(self) -> Self::Ret;
297 fn inner(self) -> Self::Ret;
298}
299
David Tolnaydaaf7742016-10-03 11:11:43 -0700300impl<'a, T> FilterAttrs<'a> for T
301 where T: IntoIterator<Item = &'a Attribute>
302{
David Tolnay4a51dc72016-10-01 00:40:31 -0700303 type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
304
305 fn outer(self) -> Self::Ret {
306 fn is_outer(attr: &&Attribute) -> bool {
Alex Crichton2e0229c2017-05-23 09:34:50 -0700307 match attr.style {
308 AttrStyle::Outer => true,
309 _ => false,
310 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700311 }
312 self.into_iter().filter(is_outer)
313 }
314
315 fn inner(self) -> Self::Ret {
316 fn is_inner(attr: &&Attribute) -> bool {
Alex Crichton2e0229c2017-05-23 09:34:50 -0700317 match attr.style {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700318 AttrStyle::Inner(_) => true,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700319 _ => false,
320 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700321 }
322 self.into_iter().filter(is_inner)
323 }
324}
325
David Tolnay86eca752016-09-04 11:26:41 -0700326#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700327pub mod parsing {
328 use super::*;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500329 use cursor::Cursor;
330 use {PResult, parse_error};
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700331 use proc_macro2::{TokenNode, Spacing, TokenTree};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700332
333 fn eq() -> TokenTree {
Alex Crichton954046c2017-05-30 21:49:42 -0700334 TokenTree {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700335 span: Default::default(),
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700336 kind: TokenNode::Op('=', Spacing::Alone),
Alex Crichton954046c2017-05-30 21:49:42 -0700337 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700338 }
339
Alex Crichton954046c2017-05-30 21:49:42 -0700340 impl Attribute {
341 #[cfg(feature = "full")]
Michael Layzell92639a52017-06-01 00:07:44 -0400342 named!(pub parse_inner -> Self, alt!(
343 do_parse!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800344 pound: punct!(#) >>
345 bang: punct!(!) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400346 path_and_tts: brackets!(tuple!(
347 call!(::Path::parse_mod_style),
David Tolnay9c76bcb2017-12-26 23:14:59 -0500348 call!(mac::parsing::parse_tt_list)
Michael Layzell92639a52017-06-01 00:07:44 -0400349 )) >>
350 ({
351 let ((path, tts), bracket) = path_and_tts;
Alex Crichton954046c2017-05-30 21:49:42 -0700352
Michael Layzell92639a52017-06-01 00:07:44 -0400353 Attribute {
354 style: AttrStyle::Inner(bang),
355 path: path,
356 tts: tts,
357 is_sugared_doc: false,
358 pound_token: pound,
359 bracket_token: bracket,
Alex Crichton954046c2017-05-30 21:49:42 -0700360 }
Michael Layzell92639a52017-06-01 00:07:44 -0400361 })
362 )
363 |
364 map!(
365 lit_doc_comment,
366 |lit| Attribute {
David Tolnayf8db7ba2017-11-11 22:52:16 -0800367 style: AttrStyle::Inner(<Token![!]>::default()),
Michael Layzell92639a52017-06-01 00:07:44 -0400368 path: "doc".into(),
369 tts: vec![
David Tolnay9c76bcb2017-12-26 23:14:59 -0500370 eq(),
371 lit,
Michael Layzell92639a52017-06-01 00:07:44 -0400372 ],
373 is_sugared_doc: true,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800374 pound_token: <Token![#]>::default(),
David Tolnay32954ef2017-12-26 22:43:16 -0500375 bracket_token: token::Bracket::default(),
Michael Layzell92639a52017-06-01 00:07:44 -0400376 }
377 )
378 ));
Alex Crichton954046c2017-05-30 21:49:42 -0700379
Michael Layzell92639a52017-06-01 00:07:44 -0400380 named!(pub parse_outer -> Self, alt!(
381 do_parse!(
David Tolnayf8db7ba2017-11-11 22:52:16 -0800382 pound: punct!(#) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400383 path_and_tts: brackets!(tuple!(
384 call!(::Path::parse_mod_style),
David Tolnay9c76bcb2017-12-26 23:14:59 -0500385 call!(mac::parsing::parse_tt_list)
Michael Layzell92639a52017-06-01 00:07:44 -0400386 )) >>
387 ({
388 let ((path, tts), bracket) = path_and_tts;
Alex Crichton954046c2017-05-30 21:49:42 -0700389
Michael Layzell92639a52017-06-01 00:07:44 -0400390 Attribute {
Alex Crichton954046c2017-05-30 21:49:42 -0700391 style: AttrStyle::Outer,
Michael Layzell92639a52017-06-01 00:07:44 -0400392 path: path,
393 tts: tts,
394 is_sugared_doc: false,
395 pound_token: pound,
396 bracket_token: bracket,
Alex Crichton954046c2017-05-30 21:49:42 -0700397 }
Michael Layzell92639a52017-06-01 00:07:44 -0400398 })
399 )
400 |
401 map!(
402 lit_doc_comment,
403 |lit| Attribute {
404 style: AttrStyle::Outer,
405 path: "doc".into(),
406 tts: vec![
David Tolnay9c76bcb2017-12-26 23:14:59 -0500407 eq(),
408 lit,
Michael Layzell92639a52017-06-01 00:07:44 -0400409 ],
410 is_sugared_doc: true,
David Tolnayf8db7ba2017-11-11 22:52:16 -0800411 pound_token: <Token![#]>::default(),
David Tolnay32954ef2017-12-26 22:43:16 -0500412 bracket_token: token::Bracket::default(),
Michael Layzell92639a52017-06-01 00:07:44 -0400413 }
414 )
415 ));
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700416 }
David Tolnayb79ee962016-09-04 09:39:20 -0700417
Michael Layzell92639a52017-06-01 00:07:44 -0400418 fn lit_doc_comment(input: Cursor) -> PResult<TokenTree> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400419 match input.literal() {
420 Some((rest, span, lit)) => {
421 let literal = lit.to_string();
422 if literal.starts_with("//") || literal.starts_with("/*") {
423 Ok((rest, TokenTree {
424 span: span,
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700425 kind: TokenNode::Literal(lit)
Michael Layzell589a8f42017-06-02 19:47:01 -0400426 }))
427 } else {
428 parse_error()
429 }
430 }
431 _ => parse_error()
Alex Crichton954046c2017-05-30 21:49:42 -0700432 }
433 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700434}
David Tolnay87d0b442016-09-04 11:52:12 -0700435
436#[cfg(feature = "printing")]
437mod printing {
438 use super::*;
439 use quote::{Tokens, ToTokens};
440
441 impl ToTokens for Attribute {
442 fn to_tokens(&self, tokens: &mut Tokens) {
Arnavion44d2bf32017-04-19 02:47:55 -0700443 // If this was a sugared doc, emit it in its original form instead of `#[doc = "..."]`
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700444 if self.is_sugared_doc {
445 if let Some(MetaItem::NameValue(ref pair)) = self.meta_item() {
446 if pair.ident == "doc" {
447 let value = pair.lit.value.to_string();
Alex Crichton954046c2017-05-30 21:49:42 -0700448 if value.starts_with('/') {
449 pair.lit.to_tokens(tokens);
450 return
David Tolnay14cbdeb2016-10-01 12:13:59 -0700451 }
David Tolnay4a51dc72016-10-01 00:40:31 -0700452 }
David Tolnayc91dd672016-10-01 01:03:56 -0700453 }
454 }
David Tolnay14cbdeb2016-10-01 12:13:59 -0700455
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700456 self.pound_token.to_tokens(tokens);
457 if let AttrStyle::Inner(ref b) = self.style {
458 b.to_tokens(tokens);
David Tolnay14cbdeb2016-10-01 12:13:59 -0700459 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700460 self.bracket_token.surround(tokens, |tokens| {
461 self.path.to_tokens(tokens);
462 tokens.append_all(&self.tts);
463 });
David Tolnay87d0b442016-09-04 11:52:12 -0700464 }
465 }
466
Alex Crichton62a0a592017-05-22 13:58:53 -0700467 impl ToTokens for MetaItemList {
David Tolnay87d0b442016-09-04 11:52:12 -0700468 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -0700469 self.ident.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700470 self.paren_token.surround(tokens, |tokens| {
471 self.nested.to_tokens(tokens);
472 })
David Tolnay87d0b442016-09-04 11:52:12 -0700473 }
474 }
David Tolnayb7fa2b62016-10-30 10:50:47 -0700475
Alex Crichton62a0a592017-05-22 13:58:53 -0700476 impl ToTokens for MetaNameValue {
David Tolnayb7fa2b62016-10-30 10:50:47 -0700477 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichton62a0a592017-05-22 13:58:53 -0700478 self.ident.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700479 self.eq_token.to_tokens(tokens);
Alex Crichton62a0a592017-05-22 13:58:53 -0700480 self.lit.to_tokens(tokens);
David Tolnayb7fa2b62016-10-30 10:50:47 -0700481 }
482 }
David Tolnay87d0b442016-09-04 11:52:12 -0700483}