1pub mod data_structures;
4pub mod version;
5
6use std::fmt::Debug;
7use std::sync::atomic::{AtomicU32, Ordering};
8
9use rustc_index::bit_set::GrowableBitSet;
10use rustc_span::{Ident, Span, Symbol, sym};
11use smallvec::{SmallVec, smallvec};
12use thin_vec::{ThinVec, thin_vec};
13
14use crate::ast::{
15 AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
16 Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
17 PathSegment, Safety, SyntheticAttr,
18};
19use crate::token::{
20 self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token,
21};
22use crate::tokenstream::{
23 DelimSpacing, DelimSpan, LazyTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
24};
25use crate::util::comments;
26use crate::util::literal::escape_string_symbol;
27
28pub struct MarkedAttrs(GrowableBitSet<AttrId>);
29
30impl MarkedAttrs {
31 pub fn new() -> Self {
32 MarkedAttrs(GrowableBitSet::new_empty())
35 }
36
37 pub fn mark(&mut self, attr: &Attribute) {
38 self.0.insert(attr.id);
39 }
40
41 pub fn is_marked(&self, attr: &Attribute) -> bool {
42 self.0.contains(attr.id)
43 }
44}
45
46pub struct AttrIdGenerator(AtomicU32);
47
48impl AttrIdGenerator {
49 pub fn new() -> Self {
50 AttrIdGenerator(AtomicU32::new(0))
51 }
52
53 pub fn mk_attr_id(&self) -> AttrId {
54 let id = self.0.fetch_add(1, Ordering::Relaxed);
55 if !(id != u32::MAX) {
::core::panicking::panic("assertion failed: id != u32::MAX")
};assert!(id != u32::MAX);
56 AttrId::from_u32(id)
57 }
58}
59
60impl Attribute {
61 pub fn get_normal_item(&self) -> &AttrItem {
62 match &self.kind {
63 AttrKind::Normal(normal) => &normal.item,
64 AttrKind::Synthetic(..) | AttrKind::DocComment(..) | AttrKind::Generated(..) => {
65 ::core::panicking::unreachable_default_msg()unreachable!()
66 }
67 }
68 }
69
70 pub fn convert_normal_to_synthetic(self, synthetic_attr: SyntheticAttr) -> Attribute {
71 match self.kind {
72 AttrKind::Normal(..) => {
73 Attribute { kind: AttrKind::Synthetic(Box::new(synthetic_attr)), ..self }
74 }
75 AttrKind::Synthetic(..) | AttrKind::DocComment(..) | AttrKind::Generated(..) => {
76 ::core::panicking::unreachable_default_msg()unreachable!()
77 }
78 }
79 }
80}
81
82impl AttributeExt for Attribute {
83 fn name(&self) -> Option<Symbol> {
85 use SyntheticAttr::*;
86 match &self.kind {
87 AttrKind::Normal(normal) => normal.item.name(),
88 AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace(_)) => None,
89 AttrKind::DocComment(..) => None,
90 AttrKind::Generated(generated) => match generated.path() {
91 [name] => Some(*name),
92 _ => None,
93 },
94 }
95 }
96
97 fn path_matches(&self, name: &[Symbol]) -> bool {
98 match &self.kind {
99 AttrKind::Normal(normal) => {
100 normal.item.path.segments.len() == name.len()
101 && normal
102 .item
103 .path
104 .segments
105 .iter()
106 .zip(name)
107 .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
108 }
109 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => false,
110 AttrKind::Generated(generated) => generated.path() == name,
111 }
112 }
113
114 fn value_str(&self) -> Option<Symbol> {
130 match &self.kind {
131 AttrKind::Normal(normal) => normal.item.value_str(),
132 AttrKind::Synthetic(..) => ::core::panicking::unreachable_default_msg()unreachable!(),
133 AttrKind::DocComment(..) => None,
134 AttrKind::Generated(generated) => generated.value_str(),
135 }
136 }
137
138 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind, Span)> {
146 match &self.kind {
147 AttrKind::DocComment(kind, data) => {
148 Some((*data, DocFragmentKind::Sugared(*kind), self.span))
149 }
150 AttrKind::Normal(normal)
151 if normal.item.path == sym::doc
152 && let Some(value) = normal.item.value_str()
153 && let Some(value_span) = normal.item.value_span() =>
154 {
155 Some((value, DocFragmentKind::Raw(value_span), self.span))
156 }
157 AttrKind::Normal(..) | AttrKind::Synthetic(..) => None,
158 AttrKind::Generated(generated) => generated.doc_str_and_fragment_kind()?,
159 }
160 }
161
162 fn doc_resolution_scope(&self) -> Option<AttrStyle> {
163 match &self.kind {
164 AttrKind::DocComment(..) => Some(self.style),
165 AttrKind::Normal(normal)
166 if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
167 {
168 Some(self.style)
169 }
170 _ => None,
171 }
172 }
173}
174
175impl Attribute {
176 pub fn style(&self) -> AttrStyle {
177 self.style
178 }
179
180 pub fn may_have_doc_links(&self) -> bool {
181 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
182 || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
183 }
184
185 pub fn meta(&self) -> Option<MetaItem> {
187 match &self.kind {
188 AttrKind::Normal(normal) => normal.item.meta(self.span),
189 AttrKind::Synthetic(..) | AttrKind::DocComment(..) | AttrKind::Generated(..) => None,
190 }
191 }
192
193 pub fn meta_kind(&self) -> Option<MetaItemKind> {
194 match &self.kind {
195 AttrKind::Normal(normal) => normal.item.meta_kind(),
196 AttrKind::Synthetic(..) => ::core::panicking::unreachable_default_msg()unreachable!(),
197 AttrKind::DocComment(..) => None,
198 AttrKind::Generated(..) => None,
199 }
200 }
201
202 pub fn append_token_trees_to(&self, res: &mut Vec<TokenTree>) {
203 match &self.kind {
204 AttrKind::Normal(normal) => normal
205 .tokens
206 .as_ref()
207 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("attribute is missing tokens: {0:?}",
self));
}panic!("attribute is missing tokens: {self:?}"))
208 .append_token_trees_to(res),
209 AttrKind::Synthetic(..) => {}
211 AttrKind::Generated(generated) => generated.append_token_trees_to(res),
212 AttrKind::DocComment(comment_kind, data) => res.push(TokenTree::token_alone(
213 token::DocComment(*comment_kind, self.style, *data),
214 self.span,
215 )),
216 }
217 }
218
219 pub fn deprecation_note(&self) -> Option<Ident> {
220 match &self.kind {
221 AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
222 let meta = &normal.item;
223
224 if let Some(s) = meta.value_str() {
226 return Some(Ident { name: s, span: meta.span });
227 }
228
229 if let Some(list) = meta.meta_item_list() {
231 for nested in list {
232 if let Some(mi) = nested.meta_item()
233 && mi.path == sym::note
234 && let Some(s) = mi.value_str()
235 {
236 return Some(Ident { name: s, span: mi.span });
237 }
238 }
239 }
240
241 None
242 }
243 _ => None,
244 }
245 }
246
247 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
255 match &self.kind {
256 AttrKind::Normal(normal) => normal.item.meta_item_list(),
257 AttrKind::Synthetic(..) | AttrKind::DocComment(..) | AttrKind::Generated(..) => None,
258 }
259 }
260
261 pub fn path_span(&self) -> Option<Span> {
262 match &self.kind {
263 AttrKind::Normal(attr) => Some(attr.item.path.span),
264 AttrKind::Synthetic(..) => ::core::panicking::unreachable_default_msg()unreachable!(),
265 AttrKind::DocComment(_, _) => None,
266 AttrKind::Generated(generated) => generated.path_span(),
267 }
268 }
269}
270
271impl AttrItem {
272 pub fn name(&self) -> Option<Symbol> {
273 if let [seg] = &*self.path.segments { Some(seg.ident.name) } else { None }
274 }
275
276 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
277 match &self.args {
278 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
279 MetaItemKind::list_from_tokens(args.tokens.clone())
280 }
281 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
282 }
283 }
284
285 fn value_str(&self) -> Option<Symbol> {
298 match &self.args {
299 AttrArgs::Eq { expr, .. } => match expr.kind {
300 ExprKind::Lit(token_lit) => {
301 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
302 }
303 _ => None,
304 },
305 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
306 }
307 }
308
309 fn value_span(&self) -> Option<Span> {
322 match &self.args {
323 AttrArgs::Eq { expr, .. } => Some(expr.span),
324 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
325 }
326 }
327
328 pub fn meta(&self, span: Span) -> Option<MetaItem> {
329 Some(MetaItem {
330 unsafety: Safety::Default,
331 path: self.path.clone(),
332 kind: self.meta_kind()?,
333 span,
334 })
335 }
336
337 pub fn meta_kind(&self) -> Option<MetaItemKind> {
338 MetaItemKind::from_attr_args(&self.args)
339 }
340}
341
342impl MetaItem {
343 pub fn ident(&self) -> Option<Ident> {
345 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
346 }
347
348 pub fn name(&self) -> Option<Symbol> {
349 self.ident().map(|ident| ident.name)
350 }
351
352 pub fn has_name(&self, name: Symbol) -> bool {
353 self.path == name
354 }
355
356 pub fn is_word(&self) -> bool {
357 #[allow(non_exhaustive_omitted_patterns)] match self.kind {
MetaItemKind::Word => true,
_ => false,
}matches!(self.kind, MetaItemKind::Word)
358 }
359
360 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
361 match &self.kind {
362 MetaItemKind::List(l) => Some(&**l),
363 _ => None,
364 }
365 }
366
367 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
373 match &self.kind {
374 MetaItemKind::NameValue(v) => Some(v),
375 _ => None,
376 }
377 }
378
379 pub fn name_value_literal_span(&self) -> Option<Span> {
387 Some(self.name_value_literal()?.span)
388 }
389
390 pub fn value_str(&self) -> Option<Symbol> {
403 match &self.kind {
404 MetaItemKind::NameValue(v) => v.kind.str(),
405 _ => None,
406 }
407 }
408
409 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
410 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
412 let path = match tt.as_deref() {
413 Some(&TokenTree::Token(
414 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
415 _,
416 )) => 'arm: {
417 let mut segments = if let &token::Ident(name, _) = kind {
418 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
419 iter.peek()
420 {
421 iter.next();
422 {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(PathSegment::from_ident(Ident::new(name, span)));
vec
}thin_vec![PathSegment::from_ident(Ident::new(name, span))]
423 } else {
424 break 'arm Path::from_ident(Ident::new(name, span));
425 }
426 } else {
427 {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(PathSegment::path_root(span));
vec
}thin_vec![PathSegment::path_root(span)]
428 };
429 loop {
430 let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
431 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
432 else {
433 return None;
434 };
435 segments.push(PathSegment::from_ident(Ident::new(name, span)));
436 let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
437 else {
438 break;
439 };
440 iter.next();
441 }
442 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
443 Path { span, segments }
444 }
445 Some(TokenTree::Delimited(
446 _span,
447 _spacing,
448 Delimiter::Invisible(InvisibleOrigin::MetaVar(
449 MetaVarKind::Meta { .. } | MetaVarKind::Path,
450 )),
451 _stream,
452 )) => {
453 ::core::panicking::unreachable_default_msg()unreachable!()
455 }
456 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
457 {
::core::panicking::panic_fmt(format_args!("Should be `TokenTree::Delimited`, not delim tokens: {0:?}",
tt));
};panic!("Should be `TokenTree::Delimited`, not delim tokens: {:?}", tt);
458 }
459 _ => return None,
460 };
461 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
462 let kind = MetaItemKind::from_tokens(iter)?;
463 let hi = match &kind {
464 MetaItemKind::NameValue(lit) => lit.span.hi(),
465 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
466 _ => path.span.hi(),
467 };
468 let span = path.span.with_hi(hi);
469 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
473 }
474}
475
476impl MetaItemKind {
477 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
479 let mut iter = tokens.iter();
480 let mut result = ThinVec::new();
481 while iter.peek().is_some() {
482 let item = MetaItemInner::from_tokens(&mut iter)?;
483 result.push(item);
484 match iter.next() {
485 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
486 _ => return None,
487 }
488 }
489 Some(result)
490 }
491
492 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
493 match iter.next() {
494 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
495 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
496 }
497 Some(TokenTree::Token(token, _)) => {
498 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
499 }
500 _ => None,
501 }
502 }
503
504 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
505 match iter.peek() {
506 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
507 let inner_tokens = inner_tokens.clone();
508 iter.next();
509 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
510 }
511 Some(TokenTree::Delimited(..)) => None,
512 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
513 iter.next();
514 MetaItemKind::name_value_from_tokens(iter)
515 }
516 _ => Some(MetaItemKind::Word),
517 }
518 }
519
520 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
521 match args {
522 AttrArgs::Empty => Some(MetaItemKind::Word),
523 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
524 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
525 }
526 AttrArgs::Delimited(..) => None,
527 AttrArgs::Eq { expr, .. } => match expr.kind {
528 ExprKind::Lit(token_lit) => {
529 MetaItemLit::from_token_lit(token_lit, expr.span)
531 .ok()
532 .map(|lit| MetaItemKind::NameValue(lit))
533 }
534 _ => None,
535 },
536 }
537 }
538}
539
540impl MetaItemInner {
541 pub fn span(&self) -> Span {
542 match self {
543 MetaItemInner::MetaItem(item) => item.span,
544 MetaItemInner::Lit(lit) => lit.span,
545 }
546 }
547
548 pub fn ident(&self) -> Option<Ident> {
550 self.meta_item().and_then(|meta_item| meta_item.ident())
551 }
552
553 pub fn name(&self) -> Option<Symbol> {
555 self.ident().map(|ident| ident.name)
556 }
557
558 pub fn has_name(&self, name: Symbol) -> bool {
560 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
561 }
562
563 pub fn is_word(&self) -> bool {
565 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
566 }
567
568 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
570 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
571 }
572
573 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
576 self.meta_item().and_then(|meta_item| {
577 meta_item.meta_item_list().and_then(|meta_item_list| {
578 if meta_item_list.len() == 1
579 && let Some(ident) = meta_item.ident()
580 && let Some(lit) = meta_item_list[0].lit()
581 {
582 return Some((ident.name, lit));
583 }
584 None
585 })
586 })
587 }
588
589 pub fn name_value_literal_span(&self) -> Option<Span> {
591 self.meta_item()?.name_value_literal_span()
592 }
593
594 pub fn value_str(&self) -> Option<Symbol> {
597 self.meta_item().and_then(|meta_item| meta_item.value_str())
598 }
599
600 pub fn lit(&self) -> Option<&MetaItemLit> {
602 match self {
603 MetaItemInner::Lit(lit) => Some(lit),
604 _ => None,
605 }
606 }
607
608 pub fn boolean_literal(&self) -> Option<bool> {
610 match self {
611 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
612 _ => None,
613 }
614 }
615
616 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
619 match self {
620 MetaItemInner::MetaItem(_item) => Some(self),
621 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
622 _ => None,
623 }
624 }
625
626 pub fn meta_item(&self) -> Option<&MetaItem> {
628 match self {
629 MetaItemInner::MetaItem(item) => Some(item),
630 _ => None,
631 }
632 }
633
634 pub fn is_meta_item(&self) -> bool {
636 self.meta_item().is_some()
637 }
638
639 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
640 match iter.peek() {
641 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
642 iter.next();
643 return Some(MetaItemInner::Lit(lit));
644 }
645 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
646 iter.next();
647 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
648 }
649 _ => {}
650 }
651 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
652 }
653}
654
655pub fn mk_doc_comment(
656 g: &AttrIdGenerator,
657 comment_kind: CommentKind,
658 style: AttrStyle,
659 data: Symbol,
660 span: Span,
661) -> Attribute {
662 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
663}
664
665pub fn mk_attr_from_item(
666 g: &AttrIdGenerator,
667 item: AttrItem,
668 tokens: Option<LazyTokenStream>,
669 style: AttrStyle,
670 span: Span,
671) -> Attribute {
672 Attribute {
673 kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
674 id: g.mk_attr_id(),
675 style,
676 span,
677 }
678}
679
680fn mk_attr_tokens(style: AttrStyle, item_tokens: TokenStream, span: Span) -> LazyTokenStream {
681 let mut tokens = match style {
682 AttrStyle::Outer => {
683 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::new(token::Pound, span),
Spacing::JointHidden)]))vec![TokenTree::Token(Token::new(token::Pound, span), Spacing::JointHidden)]
684 }
685 AttrStyle::Inner => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::new(token::Pound, span), Spacing::Joint),
TokenTree::Token(Token::new(token::Bang, span),
Spacing::JointHidden)]))vec![
686 TokenTree::Token(Token::new(token::Pound, span), Spacing::Joint),
687 TokenTree::Token(Token::new(token::Bang, span), Spacing::JointHidden),
688 ],
689 };
690 tokens.push(TokenTree::Delimited(
691 DelimSpan::from_single(span),
692 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
693 Delimiter::Bracket,
694 item_tokens,
695 ));
696
697 LazyTokenStream::new_direct(TokenStream::new(tokens))
698}
699
700pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
703 let path = Path::from_ident(Ident::new(name, span));
704 let args = AttrArgs::Empty;
705
706 let tokens = Some(mk_attr_tokens(
707 style,
708 TokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::from_ast_ident(Ident::new(name, span)),
Spacing::Alone)]))vec![TokenTree::Token(
709 Token::from_ast_ident(Ident::new(name, span)),
710 Spacing::Alone,
711 )]),
712 span,
713 ));
714
715 mk_attr_from_item(
716 g,
717 AttrItem { unsafety: Safety::Default, path, args, span },
718 tokens,
719 style,
720 span,
721 )
722}
723
724pub fn mk_attr_nested_word(
727 g: &AttrIdGenerator,
728 style: AttrStyle,
729 outer: Symbol,
730 inner: Symbol,
731 span: Span,
732) -> Attribute {
733 let inner_tokens = TokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::from_ast_ident(Ident::new(inner, span)),
Spacing::Alone)]))vec![TokenTree::Token(
734 Token::from_ast_ident(Ident::new(inner, span)),
735 Spacing::Alone,
736 )]);
737 let outer_ident = Ident::new(outer, span);
738 let path = Path::from_ident(outer_ident);
739 let attr_args = AttrArgs::Delimited(DelimArgs {
740 dspan: DelimSpan::from_single(span),
741 delim: Delimiter::Parenthesis,
742 tokens: inner_tokens,
743 });
744
745 let tokens = Some(mk_attr_tokens(
746 style,
747 TokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::from_ast_ident(Ident::new(outer, span)),
Spacing::Alone),
TokenTree::Delimited(DelimSpan::from_single(span),
DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
Delimiter::Parenthesis,
TokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::from_ast_ident(Ident::new(inner,
span)), Spacing::Alone)]))))]))vec![
748 TokenTree::Token(Token::from_ast_ident(Ident::new(outer, span)), Spacing::Alone),
749 TokenTree::Delimited(
750 DelimSpan::from_single(span),
751 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
752 Delimiter::Parenthesis,
753 TokenStream::new(vec![TokenTree::Token(
754 Token::from_ast_ident(Ident::new(inner, span)),
755 Spacing::Alone,
756 )]),
757 ),
758 ]),
759 span,
760 ));
761
762 mk_attr_from_item(
763 g,
764 AttrItem { unsafety: Safety::Default, path, args: attr_args, span },
765 tokens,
766 style,
767 span,
768 )
769}
770
771pub fn mk_attr_name_value_str(
774 g: &AttrIdGenerator,
775 style: AttrStyle,
776 name: Symbol,
777 val: Symbol,
778 span: Span,
779) -> Attribute {
780 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
781 let expr = Box::new(Expr {
782 id: DUMMY_NODE_ID,
783 kind: ExprKind::Lit(lit),
784 span,
785 attrs: AttrVec::new(),
786 tokens: None,
787 });
788 let path = Path::from_ident(Ident::new(name, span));
789 let args = AttrArgs::Eq { eq_span: span, expr };
790
791 let tokens = Some(mk_attr_tokens(
792 style,
793 TokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::Token(Token::from_ast_ident(Ident::new(name, span)),
Spacing::Alone),
TokenTree::Token(Token::new(token::Eq, span), Spacing::Alone),
TokenTree::Token(Token::new(token::TokenKind::lit(lit.kind,
lit.symbol, lit.suffix), span), Spacing::Alone)]))vec![
794 TokenTree::Token(Token::from_ast_ident(Ident::new(name, span)), Spacing::Alone),
795 TokenTree::Token(Token::new(token::Eq, span), Spacing::Alone),
796 TokenTree::Token(
797 Token::new(token::TokenKind::lit(lit.kind, lit.symbol, lit.suffix), span),
798 Spacing::Alone,
799 ),
800 ]),
801 span,
802 ));
803
804 mk_attr_from_item(
805 g,
806 AttrItem { unsafety: Safety::Default, path, args, span },
807 tokens,
808 style,
809 span,
810 )
811}
812
813pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
814 attrs.iter().filter(move |attr| attr.has_name(name))
815}
816
817pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
818 filter_by_name(attrs, name).next()
819}
820
821pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
822 find_by_name(attrs, name).and_then(|attr| attr.value_str())
823}
824
825pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
826 find_by_name(attrs, name).is_some()
827}
828
829pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
830 items.iter().any(|item| item.has_name(name))
831}
832
833impl MetaItemLit {
834 pub fn value_as_str(&self) -> Option<Symbol> {
835 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
836 }
837}
838
839pub trait AttributeExt: Debug + 'static {
840 fn name(&self) -> Option<Symbol>;
843
844 fn value_str(&self) -> Option<Symbol>;
846
847 fn path_matches(&self, name: &[Symbol]) -> bool;
851
852 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind, Span)>;
858
859 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
867}
868
869impl Attribute {
872 pub fn name(&self) -> Option<Symbol> {
873 AttributeExt::name(self)
874 }
875
876 pub fn value_str(&self) -> Option<Symbol> {
877 AttributeExt::value_str(self)
878 }
879
880 pub fn value_span(&self) -> Option<Span> {
882 match &self.kind {
883 AttrKind::Normal(normal) => match &normal.item.args {
884 AttrArgs::Eq { expr, .. } => Some(expr.span),
885 _ => None,
886 },
887 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None,
888 AttrKind::Generated(generated) => generated.value_span(),
889 }
890 }
891
892 pub fn path_matches(&self, name: &[Symbol]) -> bool {
893 AttributeExt::path_matches(self, name)
894 }
895
896 pub fn is_doc_comment(&self) -> bool {
900 match &self.kind {
901 AttrKind::Normal(..) | AttrKind::Synthetic(..) => false,
902 AttrKind::DocComment(..) => true,
903 AttrKind::Generated(generated) => generated.is_doc_comment(),
904 }
905 }
906
907 #[inline]
910 pub fn has_name(&self, name: Symbol) -> bool {
911 self.name().map(|x| x == name).unwrap_or(false)
912 }
913
914 #[inline]
917 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
918 names.iter().any(|&name| self.has_name(name))
919 }
920
921 pub fn is_word(&self) -> bool {
923 match &self.kind {
924 AttrKind::Normal(normal) => #[allow(non_exhaustive_omitted_patterns)] match normal.item.args {
AttrArgs::Empty => true,
_ => false,
}matches!(normal.item.args, AttrArgs::Empty),
925 AttrKind::Synthetic(..) => ::core::panicking::unreachable_default_msg()unreachable!(),
926 AttrKind::DocComment(..) => false,
927 AttrKind::Generated(generated) => generated.is_word(),
928 }
929 }
930
931 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
932 use SyntheticAttr::*;
933 match &self.kind {
934 AttrKind::Normal(normal) => {
935 normal.item.path.segments.iter().map(|i| i.ident.name).collect()
936 }
937 AttrKind::Synthetic(CfgTrace(_)) => {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(sym::cfg);
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::cfg])))
}
}smallvec![sym::cfg],
938 AttrKind::Synthetic(CfgAttrTrace(_)) => {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(sym::cfg_attr);
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::cfg_attr])))
}
}smallvec![sym::cfg_attr],
939 AttrKind::DocComment(_, _) => {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(sym::doc);
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[sym::doc])))
}
}smallvec![sym::doc],
940 AttrKind::Generated(generated) => generated.path().iter().copied().collect(),
941 }
942 }
943
944 pub fn doc_str(&self) -> Option<Symbol> {
949 match &self.kind {
950 AttrKind::DocComment(.., data) => Some(*data),
951 AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
952 _ => None,
953 }
954 }
955
956 pub fn is_proc_macro_attr(&self) -> bool {
959 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
960 .iter()
961 .any(|kind| self.has_name(*kind))
962 }
963
964 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind, Span)> {
965 AttributeExt::doc_str_and_fragment_kind(self)
966 }
967}