]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast/src/attr/mod.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_ast / src / attr / mod.rs
CommitLineData
e1599b0c 1//! Functions dealing with attributes and meta items.
8faf50e0 2
9fa01778 3use crate::ast;
6a06907d
XL
4use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute};
5use crate::ast::{Lit, LitKind};
60c5eb7d 6use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
f9f354fc 7use crate::ast::{Path, PathSegment};
3dfed10e 8use crate::token::{self, CommentKind, Token};
29967ef6 9use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree, TreeAndSpacing};
9fa01778 10
74b04a01 11use rustc_index::bit_set::GrowableBitSet;
6a06907d 12use rustc_span::source_map::BytePos;
f9f354fc 13use rustc_span::symbol::{sym, Ident, Symbol};
dfeec247 14use rustc_span::Span;
8faf50e0
XL
15
16use std::iter;
17
3dfed10e 18pub struct MarkedAttrs(GrowableBitSet<AttrId>);
74b04a01 19
3dfed10e
XL
20impl MarkedAttrs {
21 // We have no idea how many attributes there will be, so just
22 // initiate the vectors with 0 bits. We'll grow them as necessary.
23 pub fn new() -> Self {
24 MarkedAttrs(GrowableBitSet::new_empty())
74b04a01 25 }
74b04a01 26
3dfed10e
XL
27 pub fn mark(&mut self, attr: &Attribute) {
28 self.0.insert(attr.id);
29 }
8faf50e0 30
3dfed10e
XL
31 pub fn is_marked(&self, attr: &Attribute) -> bool {
32 self.0.contains(attr.id)
33 }
8faf50e0
XL
34}
35
8faf50e0 36impl NestedMetaItem {
e1599b0c 37 /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
8faf50e0 38 pub fn meta_item(&self) -> Option<&MetaItem> {
532ac7d7
XL
39 match *self {
40 NestedMetaItem::MetaItem(ref item) => Some(item),
dfeec247 41 _ => None,
8faf50e0
XL
42 }
43 }
44
e1599b0c 45 /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
8faf50e0 46 pub fn literal(&self) -> Option<&Lit> {
532ac7d7
XL
47 match *self {
48 NestedMetaItem::Literal(ref lit) => Some(lit),
dfeec247 49 _ => None,
8faf50e0
XL
50 }
51 }
52
9fa01778 53 /// Returns `true` if this list item is a MetaItem with a name of `name`.
3dfed10e
XL
54 pub fn has_name(&self, name: Symbol) -> bool {
55 self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
8faf50e0
XL
56 }
57
e1599b0c 58 /// For a single-segment meta item, returns its name; otherwise, returns `None`.
9fa01778
XL
59 pub fn ident(&self) -> Option<Ident> {
60 self.meta_item().and_then(|meta_item| meta_item.ident())
61 }
48663c56 62 pub fn name_or_empty(&self) -> Symbol {
29967ef6 63 self.ident().unwrap_or_else(Ident::invalid).name
8faf50e0
XL
64 }
65
e1599b0c
XL
66 /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
67 /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
8faf50e0
XL
68 pub fn value_str(&self) -> Option<Symbol> {
69 self.meta_item().and_then(|meta_item| meta_item.value_str())
70 }
71
e1599b0c 72 /// Returns a name and single literal value tuple of the `MetaItem`.
f9f354fc 73 pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> {
dfeec247
XL
74 self.meta_item().and_then(|meta_item| {
75 meta_item.meta_item_list().and_then(|meta_item_list| {
76 if meta_item_list.len() == 1 {
77 if let Some(ident) = meta_item.ident() {
78 if let Some(lit) = meta_item_list[0].literal() {
79 return Some((ident.name, lit));
8faf50e0
XL
80 }
81 }
dfeec247
XL
82 }
83 None
84 })
85 })
8faf50e0
XL
86 }
87
e1599b0c 88 /// Gets a list of inner meta items from a list `MetaItem` type.
8faf50e0
XL
89 pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
90 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
91 }
92
e1599b0c 93 /// Returns `true` if the variant is `MetaItem`.
8faf50e0
XL
94 pub fn is_meta_item(&self) -> bool {
95 self.meta_item().is_some()
96 }
97
e1599b0c 98 /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
8faf50e0 99 pub fn is_word(&self) -> bool {
9fa01778 100 self.meta_item().map_or(false, |meta_item| meta_item.is_word())
8faf50e0
XL
101 }
102
e1599b0c 103 /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
8faf50e0
XL
104 pub fn is_value_str(&self) -> bool {
105 self.value_str().is_some()
106 }
107
e1599b0c 108 /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
8faf50e0
XL
109 pub fn is_meta_item_list(&self) -> bool {
110 self.meta_item_list().is_some()
111 }
fc512014
XL
112
113 pub fn name_value_literal_span(&self) -> Option<Span> {
114 self.meta_item()?.name_value_literal_span()
115 }
8faf50e0
XL
116}
117
8faf50e0 118impl Attribute {
6a06907d 119 #[inline]
60c5eb7d
XL
120 pub fn has_name(&self, name: Symbol) -> bool {
121 match self.kind {
29967ef6 122 AttrKind::Normal(ref item, _) => item.path == name,
3dfed10e 123 AttrKind::DocComment(..) => false,
8faf50e0 124 }
8faf50e0
XL
125 }
126
e1599b0c 127 /// For a single-segment attribute, returns its name; otherwise, returns `None`.
9fa01778 128 pub fn ident(&self) -> Option<Ident> {
60c5eb7d 129 match self.kind {
29967ef6 130 AttrKind::Normal(ref item, _) => {
60c5eb7d
XL
131 if item.path.segments.len() == 1 {
132 Some(item.path.segments[0].ident)
133 } else {
134 None
135 }
136 }
3dfed10e 137 AttrKind::DocComment(..) => None,
9fa01778
XL
138 }
139 }
48663c56 140 pub fn name_or_empty(&self) -> Symbol {
29967ef6 141 self.ident().unwrap_or_else(Ident::invalid).name
8faf50e0
XL
142 }
143
144 pub fn value_str(&self) -> Option<Symbol> {
60c5eb7d 145 match self.kind {
29967ef6 146 AttrKind::Normal(ref item, _) => item.meta(self.span).and_then(|meta| meta.value_str()),
dfeec247 147 AttrKind::DocComment(..) => None,
60c5eb7d 148 }
8faf50e0
XL
149 }
150
151 pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
60c5eb7d 152 match self.kind {
29967ef6 153 AttrKind::Normal(ref item, _) => match item.meta(self.span) {
dfeec247
XL
154 Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
155 _ => None,
156 },
3dfed10e 157 AttrKind::DocComment(..) => None,
8faf50e0
XL
158 }
159 }
160
161 pub fn is_word(&self) -> bool {
29967ef6 162 if let AttrKind::Normal(item, _) = &self.kind {
60c5eb7d
XL
163 matches!(item.args, MacArgs::Empty)
164 } else {
165 false
166 }
8faf50e0
XL
167 }
168
8faf50e0
XL
169 pub fn is_meta_item_list(&self) -> bool {
170 self.meta_item_list().is_some()
171 }
172
e1599b0c 173 /// Indicates if the attribute is a `ValueString`.
8faf50e0
XL
174 pub fn is_value_str(&self) -> bool {
175 self.value_str().is_some()
176 }
fc512014
XL
177
178 /// This is used in case you want the value span instead of the whole attribute. Example:
179 ///
180 /// ```text
181 /// #[doc(alias = "foo")]
182 /// ```
183 ///
184 /// In here, it'll return a span for `"foo"`.
185 pub fn name_value_literal_span(&self) -> Option<Span> {
186 match self.kind {
187 AttrKind::Normal(ref item, _) => {
188 item.meta(self.span).and_then(|meta| meta.name_value_literal_span())
189 }
190 AttrKind::DocComment(..) => None,
191 }
192 }
8faf50e0
XL
193}
194
195impl MetaItem {
e1599b0c 196 /// For a single-segment meta item, returns its name; otherwise, returns `None`.
9fa01778 197 pub fn ident(&self) -> Option<Ident> {
dfeec247 198 if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
9fa01778 199 }
48663c56 200 pub fn name_or_empty(&self) -> Symbol {
29967ef6 201 self.ident().unwrap_or_else(Ident::invalid).name
8faf50e0
XL
202 }
203
e1599b0c
XL
204 // Example:
205 // #[attribute(name = "value")]
206 // ^^^^^^^^^^^^^^
a1dfa0c6 207 pub fn name_value_literal(&self) -> Option<&Lit> {
e74abb32 208 match &self.kind {
a1dfa0c6
XL
209 MetaItemKind::NameValue(v) => Some(v),
210 _ => None,
211 }
212 }
213
8faf50e0 214 pub fn value_str(&self) -> Option<Symbol> {
e74abb32 215 match self.kind {
dfeec247
XL
216 MetaItemKind::NameValue(ref v) => match v.kind {
217 LitKind::Str(ref s, _) => Some(*s),
218 _ => None,
8faf50e0 219 },
dfeec247 220 _ => None,
8faf50e0
XL
221 }
222 }
223
224 pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
e74abb32 225 match self.kind {
8faf50e0 226 MetaItemKind::List(ref l) => Some(&l[..]),
dfeec247 227 _ => None,
8faf50e0
XL
228 }
229 }
230
231 pub fn is_word(&self) -> bool {
5869c6ff 232 matches!(self.kind, MetaItemKind::Word)
8faf50e0
XL
233 }
234
3dfed10e 235 pub fn has_name(&self, name: Symbol) -> bool {
532ac7d7 236 self.path == name
8faf50e0
XL
237 }
238
239 pub fn is_value_str(&self) -> bool {
240 self.value_str().is_some()
241 }
fc512014
XL
242
243 /// This is used in case you want the value span instead of the whole attribute. Example:
244 ///
245 /// ```text
246 /// #[doc(alias = "foo")]
247 /// ```
248 ///
249 /// In here, it'll return a span for `"foo"`.
250 pub fn name_value_literal_span(&self) -> Option<Span> {
251 Some(self.name_value_literal()?.span)
252 }
8faf50e0
XL
253}
254
e74abb32 255impl AttrItem {
74b04a01
XL
256 pub fn span(&self) -> Span {
257 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
258 }
259
60c5eb7d 260 pub fn meta(&self, span: Span) -> Option<MetaItem> {
8faf50e0 261 Some(MetaItem {
532ac7d7 262 path: self.path.clone(),
60c5eb7d 263 kind: MetaItemKind::from_mac_args(&self.args)?,
e74abb32 264 span,
8faf50e0
XL
265 })
266 }
e74abb32 267}
8faf50e0 268
e74abb32 269impl Attribute {
60c5eb7d
XL
270 pub fn is_doc_comment(&self) -> bool {
271 match self.kind {
29967ef6 272 AttrKind::Normal(..) => false,
3dfed10e 273 AttrKind::DocComment(..) => true,
60c5eb7d 274 }
8faf50e0
XL
275 }
276
dfeec247
XL
277 pub fn doc_str(&self) -> Option<Symbol> {
278 match self.kind {
3dfed10e 279 AttrKind::DocComment(.., data) => Some(data),
29967ef6 280 AttrKind::Normal(ref item, _) if item.path == sym::doc => {
dfeec247
XL
281 item.meta(self.span).and_then(|meta| meta.value_str())
282 }
283 _ => None,
284 }
285 }
286
60c5eb7d
XL
287 pub fn get_normal_item(&self) -> &AttrItem {
288 match self.kind {
29967ef6 289 AttrKind::Normal(ref item, _) => item,
3dfed10e 290 AttrKind::DocComment(..) => panic!("unexpected doc comment"),
60c5eb7d
XL
291 }
292 }
293
294 pub fn unwrap_normal_item(self) -> AttrItem {
295 match self.kind {
29967ef6 296 AttrKind::Normal(item, _) => item,
3dfed10e 297 AttrKind::DocComment(..) => panic!("unexpected doc comment"),
60c5eb7d
XL
298 }
299 }
300
301 /// Extracts the MetaItem from inside this Attribute.
302 pub fn meta(&self) -> Option<MetaItem> {
303 match self.kind {
29967ef6 304 AttrKind::Normal(ref item, _) => item.meta(self.span),
dfeec247 305 AttrKind::DocComment(..) => None,
60c5eb7d 306 }
8faf50e0 307 }
29967ef6
XL
308
309 pub fn tokens(&self) -> TokenStream {
310 match self.kind {
311 AttrKind::Normal(_, ref tokens) => tokens
312 .as_ref()
313 .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
314 .create_token_stream(),
315 AttrKind::DocComment(comment_kind, data) => TokenStream::from(TokenTree::Token(
316 Token::new(token::DocComment(comment_kind, self.style, data), self.span),
317 )),
318 }
319 }
8faf50e0
XL
320}
321
322/* Constructors */
323
e1599b0c
XL
324pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
325 let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
326 mk_name_value_item(ident, lit_kind, str_span)
8faf50e0
XL
327}
328
416331ca 329pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
48663c56 330 let lit = Lit::from_lit_kind(lit_kind, lit_span);
416331ca 331 let span = ident.span.to(lit_span);
e74abb32 332 MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
8faf50e0
XL
333}
334
416331ca 335pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
e74abb32 336 MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
8faf50e0
XL
337}
338
339pub fn mk_word_item(ident: Ident) -> MetaItem {
e74abb32 340 MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
8faf50e0
XL
341}
342
343pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
532ac7d7 344 NestedMetaItem::MetaItem(mk_word_item(ident))
8faf50e0
XL
345}
346
416331ca 347crate fn mk_attr_id() -> AttrId {
ba9703b0 348 use std::sync::atomic::AtomicU32;
8faf50e0
XL
349 use std::sync::atomic::Ordering;
350
ba9703b0 351 static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0);
8faf50e0
XL
352
353 let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
ba9703b0
XL
354 assert!(id != u32::MAX);
355 AttrId::from_u32(id)
8faf50e0
XL
356}
357
60c5eb7d 358pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
29967ef6 359 mk_attr_from_item(AttrItem { path, args, tokens: None }, None, style, span)
60c5eb7d
XL
360}
361
29967ef6
XL
362pub fn mk_attr_from_item(
363 item: AttrItem,
364 tokens: Option<LazyTokenStream>,
365 style: AttrStyle,
366 span: Span,
367) -> Attribute {
368 Attribute { kind: AttrKind::Normal(item, tokens), id: mk_attr_id(), style, span }
8faf50e0
XL
369}
370
e1599b0c
XL
371/// Returns an inner attribute with the given value and span.
372pub fn mk_attr_inner(item: MetaItem) -> Attribute {
60c5eb7d 373 mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
e1599b0c
XL
374}
375
8faf50e0 376/// Returns an outer attribute with the given value and span.
416331ca 377pub fn mk_attr_outer(item: MetaItem) -> Attribute {
60c5eb7d 378 mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
8faf50e0
XL
379}
380
3dfed10e
XL
381pub fn mk_doc_comment(
382 comment_kind: CommentKind,
383 style: AttrStyle,
384 data: Symbol,
385 span: Span,
386) -> Attribute {
387 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
8faf50e0
XL
388}
389
48663c56 390pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
3dfed10e 391 items.iter().any(|item| item.has_name(name))
8faf50e0
XL
392}
393
394impl MetaItem {
1b1a35ee 395 fn token_trees_and_spacings(&self) -> Vec<TreeAndSpacing> {
8faf50e0 396 let mut idents = vec![];
29967ef6 397 let mut last_pos = BytePos(0_u32);
532ac7d7 398 for (i, segment) in self.path.segments.iter().enumerate() {
8faf50e0
XL
399 let is_first = i == 0;
400 if !is_first {
dfeec247
XL
401 let mod_sep_span =
402 Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt());
dc9dc135 403 idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
8faf50e0 404 }
dc9dc135 405 idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
8faf50e0
XL
406 last_pos = segment.ident.span.hi();
407 }
1b1a35ee 408 idents.extend(self.kind.token_trees_and_spacings(self.span));
e74abb32 409 idents
8faf50e0
XL
410 }
411
412 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
dfeec247
XL
413 where
414 I: Iterator<Item = TokenTree>,
8faf50e0
XL
415 {
416 // FIXME: Share code with `parse_path`.
74b04a01 417 let path = match tokens.next().map(TokenTree::uninterpolate) {
ba9703b0
XL
418 Some(TokenTree::Token(Token {
419 kind: kind @ (token::Ident(..) | token::ModSep),
420 span,
421 })) => 'arm: {
dc9dc135 422 let mut segments = if let token::Ident(name, _) = kind {
dfeec247
XL
423 if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
424 {
9fa01778 425 tokens.next();
dc9dc135 426 vec![PathSegment::from_ident(Ident::new(name, span))]
9fa01778 427 } else {
dc9dc135 428 break 'arm Path::from_ident(Ident::new(name, span));
8faf50e0 429 }
8faf50e0 430 } else {
9fa01778
XL
431 vec![PathSegment::path_root(span)]
432 };
433 loop {
dfeec247 434 if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) =
74b04a01 435 tokens.next().map(TokenTree::uninterpolate)
dfeec247 436 {
dc9dc135 437 segments.push(PathSegment::from_ident(Ident::new(name, span)));
9fa01778
XL
438 } else {
439 return None;
440 }
dfeec247
XL
441 if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
442 {
9fa01778
XL
443 tokens.next();
444 } else {
445 break;
446 }
8faf50e0 447 }
9fa01778 448 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
1b1a35ee 449 Path { span, segments, tokens: None }
8faf50e0 450 }
dc9dc135 451 Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
e74abb32 452 token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
8faf50e0
XL
453 token::Nonterminal::NtPath(ref path) => path.clone(),
454 _ => return None,
455 },
456 _ => return None,
457 };
458 let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
e74abb32
XL
459 let kind = MetaItemKind::from_tokens(tokens)?;
460 let hi = match kind {
8faf50e0 461 MetaItemKind::NameValue(ref lit) => lit.span.hi(),
532ac7d7
XL
462 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
463 _ => path.span.hi(),
8faf50e0 464 };
532ac7d7 465 let span = path.span.with_hi(hi);
e74abb32 466 Some(MetaItem { path, kind, span })
8faf50e0
XL
467 }
468}
469
470impl MetaItemKind {
60c5eb7d
XL
471 pub fn mac_args(&self, span: Span) -> MacArgs {
472 match self {
473 MetaItemKind::Word => MacArgs::Empty,
5869c6ff 474 MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.to_token()),
60c5eb7d
XL
475 MetaItemKind::List(list) => {
476 let mut tts = Vec::new();
477 for (i, item) in list.iter().enumerate() {
478 if i > 0 {
479 tts.push(TokenTree::token(token::Comma, span).into());
480 }
1b1a35ee 481 tts.extend(item.token_trees_and_spacings())
60c5eb7d
XL
482 }
483 MacArgs::Delimited(
dfeec247
XL
484 DelimSpan::from_single(span),
485 MacDelimiter::Parenthesis,
486 TokenStream::new(tts),
60c5eb7d
XL
487 )
488 }
489 }
490 }
491
1b1a35ee 492 fn token_trees_and_spacings(&self, span: Span) -> Vec<TreeAndSpacing> {
8faf50e0 493 match *self {
e74abb32 494 MetaItemKind::Word => vec![],
8faf50e0 495 MetaItemKind::NameValue(ref lit) => {
5869c6ff
XL
496 vec![
497 TokenTree::token(token::Eq, span).into(),
498 TokenTree::Token(lit.to_token()).into(),
499 ]
8faf50e0
XL
500 }
501 MetaItemKind::List(ref list) => {
502 let mut tokens = Vec::new();
503 for (i, item) in list.iter().enumerate() {
504 if i > 0 {
dc9dc135 505 tokens.push(TokenTree::token(token::Comma, span).into());
8faf50e0 506 }
1b1a35ee 507 tokens.extend(item.token_trees_and_spacings())
8faf50e0 508 }
e74abb32
XL
509 vec![
510 TokenTree::Delimited(
511 DelimSpan::from_single(span),
512 token::Paren,
74b04a01 513 TokenStream::new(tokens),
dfeec247
XL
514 )
515 .into(),
e74abb32 516 ]
8faf50e0
XL
517 }
518 }
519 }
520
60c5eb7d
XL
521 fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
522 let mut tokens = tokens.into_trees().peekable();
8faf50e0 523 let mut result = Vec::new();
5869c6ff 524 while tokens.peek().is_some() {
532ac7d7
XL
525 let item = NestedMetaItem::from_tokens(&mut tokens)?;
526 result.push(item);
8faf50e0 527 match tokens.next() {
dc9dc135 528 None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {}
8faf50e0
XL
529 _ => return None,
530 }
531 }
532 Some(MetaItemKind::List(result))
533 }
60c5eb7d
XL
534
535 fn name_value_from_tokens(
536 tokens: &mut impl Iterator<Item = TokenTree>,
537 ) -> Option<MetaItemKind> {
538 match tokens.next() {
f035d41b
XL
539 Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
540 MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
541 }
dfeec247
XL
542 Some(TokenTree::Token(token)) => {
543 Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
544 }
60c5eb7d
XL
545 _ => None,
546 }
547 }
548
549 fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
550 match args {
dfeec247
XL
551 MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => {
552 MetaItemKind::list_from_tokens(tokens.clone())
553 }
60c5eb7d 554 MacArgs::Delimited(..) => None,
5869c6ff 555 MacArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue),
60c5eb7d
XL
556 MacArgs::Empty => Some(MetaItemKind::Word),
557 }
558 }
559
560 fn from_tokens(
561 tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
562 ) -> Option<MetaItemKind> {
563 match tokens.peek() {
564 Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => {
565 let inner_tokens = inner_tokens.clone();
566 tokens.next();
567 MetaItemKind::list_from_tokens(inner_tokens)
568 }
569 Some(TokenTree::Delimited(..)) => None,
570 Some(TokenTree::Token(Token { kind: token::Eq, .. })) => {
571 tokens.next();
572 MetaItemKind::name_value_from_tokens(tokens)
573 }
574 _ => Some(MetaItemKind::Word),
575 }
576 }
8faf50e0
XL
577}
578
532ac7d7
XL
579impl NestedMetaItem {
580 pub fn span(&self) -> Span {
8faf50e0 581 match *self {
532ac7d7
XL
582 NestedMetaItem::MetaItem(ref item) => item.span,
583 NestedMetaItem::Literal(ref lit) => lit.span,
8faf50e0
XL
584 }
585 }
586
1b1a35ee 587 fn token_trees_and_spacings(&self) -> Vec<TreeAndSpacing> {
8faf50e0 588 match *self {
1b1a35ee 589 NestedMetaItem::MetaItem(ref item) => item.token_trees_and_spacings(),
5869c6ff 590 NestedMetaItem::Literal(ref lit) => vec![TokenTree::Token(lit.to_token()).into()],
8faf50e0
XL
591 }
592 }
593
532ac7d7 594 fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
dfeec247
XL
595 where
596 I: Iterator<Item = TokenTree>,
8faf50e0 597 {
f035d41b
XL
598 match tokens.peek() {
599 Some(TokenTree::Token(token)) => {
600 if let Ok(lit) = Lit::from_token(token) {
601 tokens.next();
602 return Some(NestedMetaItem::Literal(lit));
603 }
604 }
605 Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
606 let inner_tokens = inner_tokens.clone();
8faf50e0 607 tokens.next();
f035d41b 608 return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable());
8faf50e0 609 }
f035d41b 610 _ => {}
8faf50e0 611 }
532ac7d7 612 MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
8faf50e0
XL
613 }
614}