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, kw, 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 AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, LazyAttrTokenStream, Spacing,
24 TokenStream, TokenStreamIter, TokenTree,
25};
26use crate::util::comments;
27use crate::util::literal::escape_string_symbol;
28
29pub struct MarkedAttrs(GrowableBitSet<AttrId>);
30
31impl MarkedAttrs {
32 pub fn new() -> Self {
33 MarkedAttrs(GrowableBitSet::new_empty())
36 }
37
38 pub fn mark(&mut self, attr: &Attribute) {
39 self.0.insert(attr.id);
40 }
41
42 pub fn is_marked(&self, attr: &Attribute) -> bool {
43 self.0.contains(attr.id)
44 }
45}
46
47pub struct AttrIdGenerator(AtomicU32);
48
49impl AttrIdGenerator {
50 pub fn new() -> Self {
51 AttrIdGenerator(AtomicU32::new(0))
52 }
53
54 pub fn mk_attr_id(&self) -> AttrId {
55 let id = self.0.fetch_add(1, Ordering::Relaxed);
56 if !(id != u32::MAX) {
::core::panicking::panic("assertion failed: id != u32::MAX")
};assert!(id != u32::MAX);
57 AttrId::from_u32(id)
58 }
59}
60
61impl Attribute {
62 pub fn get_normal_item(&self) -> &AttrItem {
63 match &self.kind {
64 AttrKind::Normal(normal) => &normal.item,
65 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
66 }
67 }
68
69 pub fn convert_normal_to_synthetic(self, synthetic_attr: SyntheticAttr) -> Attribute {
70 match self.kind {
71 AttrKind::Normal(..) => {
72 Attribute { kind: AttrKind::Synthetic(Box::new(synthetic_attr)), ..self }
73 }
74 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
75 }
76 }
77}
78
79impl AttributeExt for Attribute {
80 fn id(&self) -> AttrId {
81 self.id
82 }
83
84 fn value_span(&self) -> Option<Span> {
85 match &self.kind {
86 AttrKind::Normal(normal) => match &normal.item.args {
87 AttrArgs::Eq { expr, .. } => Some(expr.span),
88 _ => None,
89 },
90 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None,
91 }
92 }
93
94 fn is_doc_comment(&self) -> Option<Span> {
98 match self.kind {
99 AttrKind::Normal(..) | AttrKind::Synthetic(..) => None,
100 AttrKind::DocComment(..) => Some(self.span),
101 }
102 }
103
104 fn name(&self) -> Option<Symbol> {
106 use SyntheticAttr::*;
107 match &self.kind {
108 AttrKind::Normal(normal) => normal.item.name(),
109 AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => None,
110 AttrKind::DocComment(..) => None,
111 }
112 }
113
114 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
115 use SyntheticAttr::*;
116 match &self.kind {
117 AttrKind::Normal(normal) => {
118 Some(normal.item.path.segments.iter().map(|i| i.ident.name).collect())
119 }
120 AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace) => None,
121 AttrKind::DocComment(_, _) => None,
122 }
123 }
124
125 fn path_span(&self) -> Option<Span> {
126 match &self.kind {
127 AttrKind::Normal(attr) => Some(attr.item.path.span),
128 AttrKind::Synthetic(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
129 AttrKind::DocComment(_, _) => None,
130 }
131 }
132
133 fn path_matches(&self, name: &[Symbol]) -> bool {
134 match &self.kind {
135 AttrKind::Normal(normal) => {
136 normal.item.path.segments.len() == name.len()
137 && normal
138 .item
139 .path
140 .segments
141 .iter()
142 .zip(name)
143 .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
144 }
145 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => false,
146 }
147 }
148
149 fn span(&self) -> Span {
150 self.span
151 }
152
153 fn is_word(&self) -> bool {
154 match &self.kind {
155 AttrKind::Normal(normal) => #[allow(non_exhaustive_omitted_patterns)] match normal.item.args {
AttrArgs::Empty => true,
_ => false,
}matches!(normal.item.args, AttrArgs::Empty),
156 AttrKind::Synthetic(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
157 AttrKind::DocComment(..) => false,
158 }
159 }
160
161 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
169 match &self.kind {
170 AttrKind::Normal(normal) => normal.item.meta_item_list(),
171 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None,
172 }
173 }
174
175 fn value_str(&self) -> Option<Symbol> {
191 match &self.kind {
192 AttrKind::Normal(normal) => normal.item.value_str(),
193 AttrKind::Synthetic(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
194 AttrKind::DocComment(..) => None,
195 }
196 }
197
198 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
204 match &self.kind {
205 AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))),
206 AttrKind::Normal(normal)
207 if normal.item.path == sym::doc
208 && let Some(value) = normal.item.value_str()
209 && let Some(value_span) = normal.item.value_span() =>
210 {
211 Some((value, DocFragmentKind::Raw(value_span)))
212 }
213 AttrKind::Normal(..) | AttrKind::Synthetic(..) => None,
214 }
215 }
216
217 fn doc_str(&self) -> Option<Symbol> {
222 match &self.kind {
223 AttrKind::DocComment(.., data) => Some(*data),
224 AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
225 _ => None,
226 }
227 }
228
229 fn doc_resolution_scope(&self) -> Option<AttrStyle> {
230 match &self.kind {
231 AttrKind::DocComment(..) => Some(self.style),
232 AttrKind::Normal(normal)
233 if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
234 {
235 Some(self.style)
236 }
237 _ => None,
238 }
239 }
240
241 fn is_automatically_derived_attr(&self) -> bool {
242 self.has_name(sym::automatically_derived)
243 }
244
245 fn is_doc_hidden(&self) -> bool {
246 self.has_name(sym::doc)
247 && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden))
248 }
249
250 fn is_doc_keyword_or_attribute(&self) -> bool {
251 if self.has_name(sym::doc)
252 && let Some(items) = self.meta_item_list()
253 {
254 for item in items {
255 if item.has_name(sym::keyword) || item.has_name(sym::attribute) {
256 return true;
257 }
258 }
259 }
260 false
261 }
262
263 fn is_rustc_doc_primitive(&self) -> bool {
264 self.has_name(sym::rustc_doc_primitive)
265 }
266}
267
268impl Attribute {
269 pub fn style(&self) -> AttrStyle {
270 self.style
271 }
272
273 pub fn may_have_doc_links(&self) -> bool {
274 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
275 || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
276 }
277
278 pub fn meta(&self) -> Option<MetaItem> {
280 match &self.kind {
281 AttrKind::Normal(normal) => normal.item.meta(self.span),
282 AttrKind::Synthetic(..) | AttrKind::DocComment(..) => None,
283 }
284 }
285
286 pub fn meta_kind(&self) -> Option<MetaItemKind> {
287 match &self.kind {
288 AttrKind::Normal(normal) => normal.item.meta_kind(),
289 AttrKind::Synthetic(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
290 AttrKind::DocComment(..) => None,
291 }
292 }
293
294 pub fn token_trees(&self) -> Vec<TokenTree> {
295 match self.kind {
296 AttrKind::Normal(ref normal) => normal
297 .tokens
298 .as_ref()
299 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("attribute is missing tokens: {0:?}",
self));
}panic!("attribute is missing tokens: {self:?}"))
300 .to_attr_token_stream()
301 .to_token_trees(),
302 AttrKind::Synthetic(..) => ::alloc::vec::Vec::new()vec![],
304 AttrKind::DocComment(comment_kind, data) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[TokenTree::token_alone(token::DocComment(comment_kind, self.style,
data), self.span)]))vec![TokenTree::token_alone(
305 token::DocComment(comment_kind, self.style, data),
306 self.span,
307 )],
308 }
309 }
310
311 pub fn deprecation_note(&self) -> Option<Ident> {
312 match &self.kind {
313 AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
314 let meta = &normal.item;
315
316 if let Some(s) = meta.value_str() {
318 return Some(Ident { name: s, span: meta.span });
319 }
320
321 if let Some(list) = meta.meta_item_list() {
323 for nested in list {
324 if let Some(mi) = nested.meta_item()
325 && mi.path == sym::note
326 && let Some(s) = mi.value_str()
327 {
328 return Some(Ident { name: s, span: mi.span });
329 }
330 }
331 }
332
333 None
334 }
335 _ => None,
336 }
337 }
338}
339
340impl AttrItem {
341 pub fn name(&self) -> Option<Symbol> {
342 if let [seg] = &*self.path.segments { Some(seg.ident.name) } else { None }
343 }
344
345 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
346 match &self.args {
347 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
348 MetaItemKind::list_from_tokens(args.tokens.clone())
349 }
350 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
351 }
352 }
353
354 fn value_str(&self) -> Option<Symbol> {
367 match &self.args {
368 AttrArgs::Eq { expr, .. } => match expr.kind {
369 ExprKind::Lit(token_lit) => {
370 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
371 }
372 _ => None,
373 },
374 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
375 }
376 }
377
378 fn value_span(&self) -> Option<Span> {
391 match &self.args {
392 AttrArgs::Eq { expr, .. } => Some(expr.span),
393 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
394 }
395 }
396
397 pub fn meta(&self, span: Span) -> Option<MetaItem> {
398 Some(MetaItem {
399 unsafety: Safety::Default,
400 path: self.path.clone(),
401 kind: self.meta_kind()?,
402 span,
403 })
404 }
405
406 pub fn meta_kind(&self) -> Option<MetaItemKind> {
407 MetaItemKind::from_attr_args(&self.args)
408 }
409}
410
411impl MetaItem {
412 pub fn ident(&self) -> Option<Ident> {
414 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
415 }
416
417 pub fn name(&self) -> Option<Symbol> {
418 self.ident().map(|ident| ident.name)
419 }
420
421 pub fn has_name(&self, name: Symbol) -> bool {
422 self.path == name
423 }
424
425 pub fn is_word(&self) -> bool {
426 #[allow(non_exhaustive_omitted_patterns)] match self.kind {
MetaItemKind::Word => true,
_ => false,
}matches!(self.kind, MetaItemKind::Word)
427 }
428
429 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
430 match &self.kind {
431 MetaItemKind::List(l) => Some(&**l),
432 _ => None,
433 }
434 }
435
436 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
442 match &self.kind {
443 MetaItemKind::NameValue(v) => Some(v),
444 _ => None,
445 }
446 }
447
448 pub fn name_value_literal_span(&self) -> Option<Span> {
456 Some(self.name_value_literal()?.span)
457 }
458
459 pub fn value_str(&self) -> Option<Symbol> {
472 match &self.kind {
473 MetaItemKind::NameValue(v) => v.kind.str(),
474 _ => None,
475 }
476 }
477
478 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
479 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
481 let path = match tt.as_deref() {
482 Some(&TokenTree::Token(
483 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
484 _,
485 )) => 'arm: {
486 let mut segments = if let &token::Ident(name, _) = kind {
487 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
488 iter.peek()
489 {
490 iter.next();
491 {
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))]
492 } else {
493 break 'arm Path::from_ident(Ident::new(name, span));
494 }
495 } else {
496 {
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)]
497 };
498 loop {
499 let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
500 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
501 else {
502 return None;
503 };
504 segments.push(PathSegment::from_ident(Ident::new(name, span)));
505 let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
506 else {
507 break;
508 };
509 iter.next();
510 }
511 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
512 Path { span, segments }
513 }
514 Some(TokenTree::Delimited(
515 _span,
516 _spacing,
517 Delimiter::Invisible(InvisibleOrigin::MetaVar(
518 MetaVarKind::Meta { .. } | MetaVarKind::Path,
519 )),
520 _stream,
521 )) => {
522 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
524 }
525 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
526 {
::core::panicking::panic_fmt(format_args!("Should be `AttrTokenTree::Delimited`, not delim tokens: {0:?}",
tt));
};panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
527 }
528 _ => return None,
529 };
530 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
531 let kind = MetaItemKind::from_tokens(iter)?;
532 let hi = match &kind {
533 MetaItemKind::NameValue(lit) => lit.span.hi(),
534 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
535 _ => path.span.hi(),
536 };
537 let span = path.span.with_hi(hi);
538 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
542 }
543}
544
545impl MetaItemKind {
546 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
548 let mut iter = tokens.iter();
549 let mut result = ThinVec::new();
550 while iter.peek().is_some() {
551 let item = MetaItemInner::from_tokens(&mut iter)?;
552 result.push(item);
553 match iter.next() {
554 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
555 _ => return None,
556 }
557 }
558 Some(result)
559 }
560
561 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
562 match iter.next() {
563 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
564 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
565 }
566 Some(TokenTree::Token(token, _)) => {
567 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
568 }
569 _ => None,
570 }
571 }
572
573 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
574 match iter.peek() {
575 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
576 let inner_tokens = inner_tokens.clone();
577 iter.next();
578 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
579 }
580 Some(TokenTree::Delimited(..)) => None,
581 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
582 iter.next();
583 MetaItemKind::name_value_from_tokens(iter)
584 }
585 _ => Some(MetaItemKind::Word),
586 }
587 }
588
589 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
590 match args {
591 AttrArgs::Empty => Some(MetaItemKind::Word),
592 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
593 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
594 }
595 AttrArgs::Delimited(..) => None,
596 AttrArgs::Eq { expr, .. } => match expr.kind {
597 ExprKind::Lit(token_lit) => {
598 MetaItemLit::from_token_lit(token_lit, expr.span)
600 .ok()
601 .map(|lit| MetaItemKind::NameValue(lit))
602 }
603 _ => None,
604 },
605 }
606 }
607}
608
609impl MetaItemInner {
610 pub fn span(&self) -> Span {
611 match self {
612 MetaItemInner::MetaItem(item) => item.span,
613 MetaItemInner::Lit(lit) => lit.span,
614 }
615 }
616
617 pub fn ident(&self) -> Option<Ident> {
619 self.meta_item().and_then(|meta_item| meta_item.ident())
620 }
621
622 pub fn name(&self) -> Option<Symbol> {
624 self.ident().map(|ident| ident.name)
625 }
626
627 pub fn has_name(&self, name: Symbol) -> bool {
629 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
630 }
631
632 pub fn is_word(&self) -> bool {
634 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
635 }
636
637 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
639 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
640 }
641
642 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
645 self.meta_item().and_then(|meta_item| {
646 meta_item.meta_item_list().and_then(|meta_item_list| {
647 if meta_item_list.len() == 1
648 && let Some(ident) = meta_item.ident()
649 && let Some(lit) = meta_item_list[0].lit()
650 {
651 return Some((ident.name, lit));
652 }
653 None
654 })
655 })
656 }
657
658 pub fn name_value_literal_span(&self) -> Option<Span> {
660 self.meta_item()?.name_value_literal_span()
661 }
662
663 pub fn value_str(&self) -> Option<Symbol> {
666 self.meta_item().and_then(|meta_item| meta_item.value_str())
667 }
668
669 pub fn lit(&self) -> Option<&MetaItemLit> {
671 match self {
672 MetaItemInner::Lit(lit) => Some(lit),
673 _ => None,
674 }
675 }
676
677 pub fn boolean_literal(&self) -> Option<bool> {
679 match self {
680 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
681 _ => None,
682 }
683 }
684
685 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
688 match self {
689 MetaItemInner::MetaItem(_item) => Some(self),
690 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
691 _ => None,
692 }
693 }
694
695 pub fn meta_item(&self) -> Option<&MetaItem> {
697 match self {
698 MetaItemInner::MetaItem(item) => Some(item),
699 _ => None,
700 }
701 }
702
703 pub fn is_meta_item(&self) -> bool {
705 self.meta_item().is_some()
706 }
707
708 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
709 match iter.peek() {
710 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
711 iter.next();
712 return Some(MetaItemInner::Lit(lit));
713 }
714 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
715 iter.next();
716 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
717 }
718 _ => {}
719 }
720 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
721 }
722}
723
724pub fn mk_doc_comment(
725 g: &AttrIdGenerator,
726 comment_kind: CommentKind,
727 style: AttrStyle,
728 data: Symbol,
729 span: Span,
730) -> Attribute {
731 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
732}
733
734pub fn mk_attr_from_item(
735 g: &AttrIdGenerator,
736 item: AttrItem,
737 tokens: Option<LazyAttrTokenStream>,
738 style: AttrStyle,
739 span: Span,
740) -> Attribute {
741 Attribute {
742 kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
743 id: g.mk_attr_id(),
744 style,
745 span,
746 }
747}
748
749fn mk_attr_tokens(
750 style: AttrStyle,
751 unsafety: Safety,
752 item_tokens: AttrTokenStream,
753 span: Span,
754) -> LazyAttrTokenStream {
755 let safety_kw = match unsafety {
756 Safety::Default => None,
757 Safety::Unsafe(span) => Some((kw::Unsafe, span)),
758 Safety::Safe(span) => Some((kw::Safe, span)),
759 };
760 let item_tokens = if let Some((kw, kw_span)) = safety_kw {
761 AttrTokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::from_ast_ident(Ident::new(kw, kw_span)),
Spacing::Alone),
AttrTokenTree::Delimited(DelimSpan::from_single(span),
DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
Delimiter::Parenthesis, item_tokens)]))vec![
762 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(kw, kw_span)), Spacing::Alone),
763 AttrTokenTree::Delimited(
764 DelimSpan::from_single(span),
765 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
766 Delimiter::Parenthesis,
767 item_tokens,
768 ),
769 ])
770 } else {
771 item_tokens
772 };
773
774 let mut tokens = match style {
775 AttrStyle::Outer => {
776 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::new(token::Pound, span),
Spacing::JointHidden)]))vec![AttrTokenTree::Token(Token::new(token::Pound, span), Spacing::JointHidden)]
777 }
778 AttrStyle::Inner => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::new(token::Pound, span), Spacing::Joint),
AttrTokenTree::Token(Token::new(token::Bang, span),
Spacing::JointHidden)]))vec![
779 AttrTokenTree::Token(Token::new(token::Pound, span), Spacing::Joint),
780 AttrTokenTree::Token(Token::new(token::Bang, span), Spacing::JointHidden),
781 ],
782 };
783 tokens.push(AttrTokenTree::Delimited(
784 DelimSpan::from_single(span),
785 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
786 Delimiter::Bracket,
787 item_tokens,
788 ));
789
790 LazyAttrTokenStream::new_direct(AttrTokenStream::new(tokens))
791}
792
793pub fn mk_attr_word(
796 g: &AttrIdGenerator,
797 style: AttrStyle,
798 unsafety: Safety,
799 name: Symbol,
800 span: Span,
801) -> Attribute {
802 let path = Path::from_ident(Ident::new(name, span));
803 let args = AttrArgs::Empty;
804
805 let tokens = Some(mk_attr_tokens(
806 style,
807 unsafety,
808 AttrTokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::from_ast_ident(Ident::new(name, span)),
Spacing::Alone)]))vec![AttrTokenTree::Token(
809 Token::from_ast_ident(Ident::new(name, span)),
810 Spacing::Alone,
811 )]),
812 span,
813 ));
814
815 mk_attr_from_item(g, AttrItem { unsafety, path, args, span }, tokens, style, span)
816}
817
818pub fn mk_attr_nested_word(
821 g: &AttrIdGenerator,
822 style: AttrStyle,
823 unsafety: Safety,
824 outer: Symbol,
825 inner: Symbol,
826 span: Span,
827) -> Attribute {
828 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(
829 Token::from_ast_ident(Ident::new(inner, span)),
830 Spacing::Alone,
831 )]);
832 let outer_ident = Ident::new(outer, span);
833 let path = Path::from_ident(outer_ident);
834 let attr_args = AttrArgs::Delimited(DelimArgs {
835 dspan: DelimSpan::from_single(span),
836 delim: Delimiter::Parenthesis,
837 tokens: inner_tokens,
838 });
839
840 let tokens = Some(mk_attr_tokens(
841 style,
842 unsafety,
843 AttrTokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::from_ast_ident(Ident::new(outer, span)),
Spacing::Alone),
AttrTokenTree::Delimited(DelimSpan::from_single(span),
DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
Delimiter::Parenthesis,
AttrTokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::from_ast_ident(Ident::new(inner,
span)), Spacing::Alone)]))))]))vec![
844 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(outer, span)), Spacing::Alone),
845 AttrTokenTree::Delimited(
846 DelimSpan::from_single(span),
847 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
848 Delimiter::Parenthesis,
849 AttrTokenStream::new(vec![AttrTokenTree::Token(
850 Token::from_ast_ident(Ident::new(inner, span)),
851 Spacing::Alone,
852 )]),
853 ),
854 ]),
855 span,
856 ));
857
858 mk_attr_from_item(g, AttrItem { unsafety, path, args: attr_args, span }, tokens, style, span)
859}
860
861pub fn mk_attr_name_value_str(
864 g: &AttrIdGenerator,
865 style: AttrStyle,
866 unsafety: Safety,
867 name: Symbol,
868 val: Symbol,
869 span: Span,
870) -> Attribute {
871 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
872 let expr = Box::new(Expr {
873 id: DUMMY_NODE_ID,
874 kind: ExprKind::Lit(lit),
875 span,
876 attrs: AttrVec::new(),
877 tokens: None,
878 });
879 let path = Path::from_ident(Ident::new(name, span));
880 let args = AttrArgs::Eq { eq_span: span, expr };
881
882 let tokens = Some(mk_attr_tokens(
883 style,
884 unsafety,
885 AttrTokenStream::new(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[AttrTokenTree::Token(Token::from_ast_ident(Ident::new(name, span)),
Spacing::Alone),
AttrTokenTree::Token(Token::new(token::Eq, span),
Spacing::Alone),
AttrTokenTree::Token(Token::new(token::TokenKind::lit(lit.kind,
lit.symbol, lit.suffix), span), Spacing::Alone)]))vec![
886 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(name, span)), Spacing::Alone),
887 AttrTokenTree::Token(Token::new(token::Eq, span), Spacing::Alone),
888 AttrTokenTree::Token(
889 Token::new(token::TokenKind::lit(lit.kind, lit.symbol, lit.suffix), span),
890 Spacing::Alone,
891 ),
892 ]),
893 span,
894 ));
895
896 mk_attr_from_item(g, AttrItem { unsafety, path, args, span }, tokens, style, span)
897}
898
899pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
900 attrs.iter().filter(move |attr| attr.has_name(name))
901}
902
903pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
904 filter_by_name(attrs, name).next()
905}
906
907pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
908 find_by_name(attrs, name).and_then(|attr| attr.value_str())
909}
910
911pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
912 find_by_name(attrs, name).is_some()
913}
914
915pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
916 items.iter().any(|item| item.has_name(name))
917}
918
919impl MetaItemLit {
920 pub fn value_as_str(&self) -> Option<Symbol> {
921 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
922 }
923}
924
925pub trait AttributeExt: Debug {
926 fn id(&self) -> AttrId;
927
928 fn name(&self) -> Option<Symbol>;
931
932 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
934
935 fn value_str(&self) -> Option<Symbol>;
937
938 fn value_span(&self) -> Option<Span>;
940
941 fn path_matches(&self, name: &[Symbol]) -> bool;
945
946 fn is_doc_comment(&self) -> Option<Span>;
950
951 #[inline]
954 fn has_name(&self, name: Symbol) -> bool {
955 self.name().map(|x| x == name).unwrap_or(false)
956 }
957
958 #[inline]
961 fn has_any_name(&self, names: &[Symbol]) -> bool {
962 names.iter().any(|&name| self.has_name(name))
963 }
964
965 fn span(&self) -> Span;
967
968 fn is_word(&self) -> bool;
970
971 fn path(&self) -> SmallVec<[Symbol; 1]> {
972 self.symbol_path().unwrap_or({
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])
973 }
974
975 fn path_span(&self) -> Option<Span>;
976
977 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
979
980 fn doc_str(&self) -> Option<Symbol>;
985
986 fn is_proc_macro_attr(&self) -> bool {
989 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
990 .iter()
991 .any(|kind| self.has_name(*kind))
992 }
993 fn is_automatically_derived_attr(&self) -> bool;
995
996 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
1002
1003 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
1011
1012 fn is_doc_hidden(&self) -> bool;
1014
1015 fn is_doc_keyword_or_attribute(&self) -> bool;
1017
1018 fn is_rustc_doc_primitive(&self) -> bool;
1020}
1021
1022impl Attribute {
1025 pub fn id(&self) -> AttrId {
1026 AttributeExt::id(self)
1027 }
1028
1029 pub fn name(&self) -> Option<Symbol> {
1030 AttributeExt::name(self)
1031 }
1032
1033 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
1034 AttributeExt::meta_item_list(self)
1035 }
1036
1037 pub fn value_str(&self) -> Option<Symbol> {
1038 AttributeExt::value_str(self)
1039 }
1040
1041 pub fn value_span(&self) -> Option<Span> {
1042 AttributeExt::value_span(self)
1043 }
1044
1045 pub fn path_matches(&self, name: &[Symbol]) -> bool {
1046 AttributeExt::path_matches(self, name)
1047 }
1048
1049 pub fn is_doc_comment(&self) -> bool {
1051 AttributeExt::is_doc_comment(self).is_some()
1052 }
1053
1054 #[inline]
1055 pub fn has_name(&self, name: Symbol) -> bool {
1056 AttributeExt::has_name(self, name)
1057 }
1058
1059 #[inline]
1060 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
1061 AttributeExt::has_any_name(self, names)
1062 }
1063
1064 pub fn span(&self) -> Span {
1065 AttributeExt::span(self)
1066 }
1067
1068 pub fn is_word(&self) -> bool {
1069 AttributeExt::is_word(self)
1070 }
1071
1072 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
1073 AttributeExt::path(self)
1074 }
1075
1076 pub fn doc_str(&self) -> Option<Symbol> {
1077 AttributeExt::doc_str(self)
1078 }
1079
1080 pub fn is_proc_macro_attr(&self) -> bool {
1081 AttributeExt::is_proc_macro_attr(self)
1082 }
1083
1084 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
1085 AttributeExt::doc_str_and_fragment_kind(self)
1086 }
1087}