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 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 item_tokens: AttrTokenStream,
752 span: Span,
753) -> LazyAttrTokenStream {
754 let mut tokens = match style {
755 AttrStyle::Outer => {
756 ::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)]
757 }
758 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![
759 AttrTokenTree::Token(Token::new(token::Pound, span), Spacing::Joint),
760 AttrTokenTree::Token(Token::new(token::Bang, span), Spacing::JointHidden),
761 ],
762 };
763 tokens.push(AttrTokenTree::Delimited(
764 DelimSpan::from_single(span),
765 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
766 Delimiter::Bracket,
767 item_tokens,
768 ));
769
770 LazyAttrTokenStream::new_direct(AttrTokenStream::new(tokens))
771}
772
773pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
776 let path = Path::from_ident(Ident::new(name, span));
777 let args = AttrArgs::Empty;
778
779 let tokens = Some(mk_attr_tokens(
780 style,
781 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(
782 Token::from_ast_ident(Ident::new(name, span)),
783 Spacing::Alone,
784 )]),
785 span,
786 ));
787
788 mk_attr_from_item(
789 g,
790 AttrItem { unsafety: Safety::Default, path, args, span },
791 tokens,
792 style,
793 span,
794 )
795}
796
797pub fn mk_attr_nested_word(
800 g: &AttrIdGenerator,
801 style: AttrStyle,
802 outer: Symbol,
803 inner: Symbol,
804 span: Span,
805) -> Attribute {
806 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(
807 Token::from_ast_ident(Ident::new(inner, span)),
808 Spacing::Alone,
809 )]);
810 let outer_ident = Ident::new(outer, span);
811 let path = Path::from_ident(outer_ident);
812 let attr_args = AttrArgs::Delimited(DelimArgs {
813 dspan: DelimSpan::from_single(span),
814 delim: Delimiter::Parenthesis,
815 tokens: inner_tokens,
816 });
817
818 let tokens = Some(mk_attr_tokens(
819 style,
820 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![
821 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(outer, span)), Spacing::Alone),
822 AttrTokenTree::Delimited(
823 DelimSpan::from_single(span),
824 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
825 Delimiter::Parenthesis,
826 AttrTokenStream::new(vec![AttrTokenTree::Token(
827 Token::from_ast_ident(Ident::new(inner, span)),
828 Spacing::Alone,
829 )]),
830 ),
831 ]),
832 span,
833 ));
834
835 mk_attr_from_item(
836 g,
837 AttrItem { unsafety: Safety::Default, path, args: attr_args, span },
838 tokens,
839 style,
840 span,
841 )
842}
843
844pub fn mk_attr_name_value_str(
847 g: &AttrIdGenerator,
848 style: AttrStyle,
849 name: Symbol,
850 val: Symbol,
851 span: Span,
852) -> Attribute {
853 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
854 let expr = Box::new(Expr {
855 id: DUMMY_NODE_ID,
856 kind: ExprKind::Lit(lit),
857 span,
858 attrs: AttrVec::new(),
859 tokens: None,
860 });
861 let path = Path::from_ident(Ident::new(name, span));
862 let args = AttrArgs::Eq { eq_span: span, expr };
863
864 let tokens = Some(mk_attr_tokens(
865 style,
866 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![
867 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(name, span)), Spacing::Alone),
868 AttrTokenTree::Token(Token::new(token::Eq, span), Spacing::Alone),
869 AttrTokenTree::Token(
870 Token::new(token::TokenKind::lit(lit.kind, lit.symbol, lit.suffix), span),
871 Spacing::Alone,
872 ),
873 ]),
874 span,
875 ));
876
877 mk_attr_from_item(
878 g,
879 AttrItem { unsafety: Safety::Default, path, args, span },
880 tokens,
881 style,
882 span,
883 )
884}
885
886pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
887 attrs.iter().filter(move |attr| attr.has_name(name))
888}
889
890pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
891 filter_by_name(attrs, name).next()
892}
893
894pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
895 find_by_name(attrs, name).and_then(|attr| attr.value_str())
896}
897
898pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
899 find_by_name(attrs, name).is_some()
900}
901
902pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
903 items.iter().any(|item| item.has_name(name))
904}
905
906impl MetaItemLit {
907 pub fn value_as_str(&self) -> Option<Symbol> {
908 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
909 }
910}
911
912pub trait AttributeExt: Debug {
913 fn id(&self) -> AttrId;
914
915 fn name(&self) -> Option<Symbol>;
918
919 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
921
922 fn value_str(&self) -> Option<Symbol>;
924
925 fn value_span(&self) -> Option<Span>;
927
928 fn path_matches(&self, name: &[Symbol]) -> bool;
932
933 fn is_doc_comment(&self) -> Option<Span>;
937
938 #[inline]
941 fn has_name(&self, name: Symbol) -> bool {
942 self.name().map(|x| x == name).unwrap_or(false)
943 }
944
945 #[inline]
948 fn has_any_name(&self, names: &[Symbol]) -> bool {
949 names.iter().any(|&name| self.has_name(name))
950 }
951
952 fn span(&self) -> Span;
954
955 fn is_word(&self) -> bool;
957
958 fn path(&self) -> SmallVec<[Symbol; 1]> {
959 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])
960 }
961
962 fn path_span(&self) -> Option<Span>;
963
964 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
966
967 fn doc_str(&self) -> Option<Symbol>;
972
973 fn is_proc_macro_attr(&self) -> bool {
976 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
977 .iter()
978 .any(|kind| self.has_name(*kind))
979 }
980 fn is_automatically_derived_attr(&self) -> bool;
982
983 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
989
990 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
998
999 fn is_doc_hidden(&self) -> bool;
1001
1002 fn is_doc_keyword_or_attribute(&self) -> bool;
1004
1005 fn is_rustc_doc_primitive(&self) -> bool;
1007}
1008
1009impl Attribute {
1012 pub fn id(&self) -> AttrId {
1013 AttributeExt::id(self)
1014 }
1015
1016 pub fn name(&self) -> Option<Symbol> {
1017 AttributeExt::name(self)
1018 }
1019
1020 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
1021 AttributeExt::meta_item_list(self)
1022 }
1023
1024 pub fn value_str(&self) -> Option<Symbol> {
1025 AttributeExt::value_str(self)
1026 }
1027
1028 pub fn value_span(&self) -> Option<Span> {
1029 AttributeExt::value_span(self)
1030 }
1031
1032 pub fn path_matches(&self, name: &[Symbol]) -> bool {
1033 AttributeExt::path_matches(self, name)
1034 }
1035
1036 pub fn is_doc_comment(&self) -> bool {
1038 AttributeExt::is_doc_comment(self).is_some()
1039 }
1040
1041 #[inline]
1042 pub fn has_name(&self, name: Symbol) -> bool {
1043 AttributeExt::has_name(self, name)
1044 }
1045
1046 #[inline]
1047 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
1048 AttributeExt::has_any_name(self, names)
1049 }
1050
1051 pub fn span(&self) -> Span {
1052 AttributeExt::span(self)
1053 }
1054
1055 pub fn is_word(&self) -> bool {
1056 AttributeExt::is_word(self)
1057 }
1058
1059 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
1060 AttributeExt::path(self)
1061 }
1062
1063 pub fn doc_str(&self) -> Option<Symbol> {
1064 AttributeExt::doc_str(self)
1065 }
1066
1067 pub fn is_proc_macro_attr(&self) -> bool {
1068 AttributeExt::is_proc_macro_attr(self)
1069 }
1070
1071 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
1072 AttributeExt::doc_str_and_fragment_kind(self)
1073 }
1074}