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