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::AttrItemKind;
15use crate::ast::{
16 AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
17 Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
18 PathSegment, Safety,
19};
20use crate::token::{
21 self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token,
22};
23use crate::tokenstream::{
24 AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, LazyAttrTokenStream, Spacing,
25 TokenStream, TokenStreamIter, TokenTree,
26};
27use crate::util::comments;
28use crate::util::literal::escape_string_symbol;
29
30pub struct MarkedAttrs(GrowableBitSet<AttrId>);
31
32impl MarkedAttrs {
33 pub fn new() -> Self {
34 MarkedAttrs(GrowableBitSet::new_empty())
37 }
38
39 pub fn mark(&mut self, attr: &Attribute) {
40 self.0.insert(attr.id);
41 }
42
43 pub fn is_marked(&self, attr: &Attribute) -> bool {
44 self.0.contains(attr.id)
45 }
46}
47
48pub struct AttrIdGenerator(AtomicU32);
49
50impl AttrIdGenerator {
51 pub fn new() -> Self {
52 AttrIdGenerator(AtomicU32::new(0))
53 }
54
55 pub fn mk_attr_id(&self) -> AttrId {
56 let id = self.0.fetch_add(1, Ordering::Relaxed);
57 if !(id != u32::MAX) {
::core::panicking::panic("assertion failed: id != u32::MAX")
};assert!(id != u32::MAX);
58 AttrId::from_u32(id)
59 }
60}
61
62impl Attribute {
63 pub fn get_normal_item(&self) -> &AttrItem {
64 match &self.kind {
65 AttrKind::Normal(normal) => &normal.item,
66 AttrKind::DocComment(..) => { ::core::panicking::panic_fmt(format_args!("unexpected doc comment")); }panic!("unexpected doc comment"),
67 }
68 }
69
70 pub fn replace_args(&mut self, new_args: AttrItemKind) {
73 match &mut self.kind {
74 AttrKind::Normal(normal) => normal.item.args = new_args,
75 AttrKind::DocComment(..) => { ::core::panicking::panic_fmt(format_args!("unexpected doc comment")); }panic!("unexpected doc comment"),
76 }
77 }
78
79 pub fn unwrap_normal_item(self) -> AttrItem {
80 match self.kind {
81 AttrKind::Normal(normal) => normal.item,
82 AttrKind::DocComment(..) => { ::core::panicking::panic_fmt(format_args!("unexpected doc comment")); }panic!("unexpected doc comment"),
83 }
84 }
85}
86
87impl AttributeExt for Attribute {
88 fn id(&self) -> AttrId {
89 self.id
90 }
91
92 fn value_span(&self) -> Option<Span> {
93 match &self.kind {
94 AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
95 AttrArgs::Eq { expr, .. } => Some(expr.span),
96 _ => None,
97 },
98 AttrKind::DocComment(..) => None,
99 }
100 }
101
102 fn is_doc_comment(&self) -> Option<Span> {
106 match self.kind {
107 AttrKind::Normal(..) => None,
108 AttrKind::DocComment(..) => Some(self.span),
109 }
110 }
111
112 fn name(&self) -> Option<Symbol> {
114 match &self.kind {
115 AttrKind::Normal(normal) => {
116 if let [ident] = &*normal.item.path.segments {
117 Some(ident.ident.name)
118 } else {
119 None
120 }
121 }
122 AttrKind::DocComment(..) => None,
123 }
124 }
125
126 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
127 match &self.kind {
128 AttrKind::Normal(p) => {
129 Some(p.item.path.segments.iter().map(|i| i.ident.name).collect())
130 }
131 AttrKind::DocComment(_, _) => None,
132 }
133 }
134
135 fn path_span(&self) -> Option<Span> {
136 match &self.kind {
137 AttrKind::Normal(attr) => Some(attr.item.path.span),
138 AttrKind::DocComment(_, _) => None,
139 }
140 }
141
142 fn path_matches(&self, name: &[Symbol]) -> bool {
143 match &self.kind {
144 AttrKind::Normal(normal) => {
145 normal.item.path.segments.len() == name.len()
146 && normal
147 .item
148 .path
149 .segments
150 .iter()
151 .zip(name)
152 .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
153 }
154 AttrKind::DocComment(..) => false,
155 }
156 }
157
158 fn span(&self) -> Span {
159 self.span
160 }
161
162 fn is_word(&self) -> bool {
163 if let AttrKind::Normal(normal) = &self.kind {
164 #[allow(non_exhaustive_omitted_patterns)] match normal.item.args {
AttrItemKind::Unparsed(AttrArgs::Empty) => true,
_ => false,
}matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
165 } else {
166 false
167 }
168 }
169
170 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
178 match &self.kind {
179 AttrKind::Normal(normal) => normal.item.meta_item_list(),
180 AttrKind::DocComment(..) => None,
181 }
182 }
183
184 fn value_str(&self) -> Option<Symbol> {
200 match &self.kind {
201 AttrKind::Normal(normal) => normal.item.value_str(),
202 AttrKind::DocComment(..) => None,
203 }
204 }
205
206 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
212 match &self.kind {
213 AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))),
214 AttrKind::Normal(normal) if normal.item.path == sym::doc => {
215 if let Some(value) = normal.item.value_str()
216 && let Some(value_span) = normal.item.value_span()
217 {
218 Some((value, DocFragmentKind::Raw(value_span)))
219 } else {
220 None
221 }
222 }
223 _ => None,
224 }
225 }
226
227 fn doc_str(&self) -> Option<Symbol> {
232 match &self.kind {
233 AttrKind::DocComment(.., data) => Some(*data),
234 AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
235 _ => None,
236 }
237 }
238
239 fn doc_resolution_scope(&self) -> Option<AttrStyle> {
240 match &self.kind {
241 AttrKind::DocComment(..) => Some(self.style),
242 AttrKind::Normal(normal)
243 if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
244 {
245 Some(self.style)
246 }
247 _ => None,
248 }
249 }
250
251 fn is_automatically_derived_attr(&self) -> bool {
252 self.has_name(sym::automatically_derived)
253 }
254
255 fn is_doc_hidden(&self) -> bool {
256 self.has_name(sym::doc)
257 && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden))
258 }
259
260 fn is_doc_keyword_or_attribute(&self) -> bool {
261 if self.has_name(sym::doc)
262 && let Some(items) = self.meta_item_list()
263 {
264 for item in items {
265 if item.has_name(sym::keyword) || item.has_name(sym::attribute) {
266 return true;
267 }
268 }
269 }
270 false
271 }
272
273 fn is_rustc_doc_primitive(&self) -> bool {
274 self.has_name(sym::rustc_doc_primitive)
275 }
276}
277
278impl Attribute {
279 pub fn style(&self) -> AttrStyle {
280 self.style
281 }
282
283 pub fn may_have_doc_links(&self) -> bool {
284 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
285 || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
286 }
287
288 pub fn meta(&self) -> Option<MetaItem> {
290 match &self.kind {
291 AttrKind::Normal(normal) => normal.item.meta(self.span),
292 AttrKind::DocComment(..) => None,
293 }
294 }
295
296 pub fn meta_kind(&self) -> Option<MetaItemKind> {
297 match &self.kind {
298 AttrKind::Normal(normal) => normal.item.meta_kind(),
299 AttrKind::DocComment(..) => None,
300 }
301 }
302
303 pub fn token_trees(&self) -> Vec<TokenTree> {
304 match self.kind {
305 AttrKind::Normal(ref normal) => normal
306 .tokens
307 .as_ref()
308 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("attribute is missing tokens: {0:?}",
self));
}panic!("attribute is missing tokens: {self:?}"))
309 .to_attr_token_stream()
310 .to_token_trees(),
311 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(
312 token::DocComment(comment_kind, self.style, data),
313 self.span,
314 )],
315 }
316 }
317
318 pub fn deprecation_note(&self) -> Option<Ident> {
319 match &self.kind {
320 AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
321 let meta = &normal.item;
322
323 if let Some(s) = meta.value_str() {
325 return Some(Ident { name: s, span: meta.span() });
326 }
327
328 if let Some(list) = meta.meta_item_list() {
330 for nested in list {
331 if let Some(mi) = nested.meta_item()
332 && mi.path == sym::note
333 && let Some(s) = mi.value_str()
334 {
335 return Some(Ident { name: s, span: mi.span });
336 }
337 }
338 }
339
340 None
341 }
342 _ => None,
343 }
344 }
345}
346
347impl AttrItem {
348 pub fn span(&self) -> Span {
349 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
350 }
351
352 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
353 match &self.args.unparsed_ref()? {
354 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
355 MetaItemKind::list_from_tokens(args.tokens.clone())
356 }
357 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
358 }
359 }
360
361 fn value_str(&self) -> Option<Symbol> {
374 match &self.args.unparsed_ref()? {
375 AttrArgs::Eq { expr, .. } => match expr.kind {
376 ExprKind::Lit(token_lit) => {
377 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
378 }
379 _ => None,
380 },
381 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
382 }
383 }
384
385 fn value_span(&self) -> Option<Span> {
398 match &self.args.unparsed_ref()? {
399 AttrArgs::Eq { expr, .. } => Some(expr.span),
400 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
401 }
402 }
403
404 pub fn meta(&self, span: Span) -> Option<MetaItem> {
405 Some(MetaItem {
406 unsafety: Safety::Default,
407 path: self.path.clone(),
408 kind: self.meta_kind()?,
409 span,
410 })
411 }
412
413 pub fn meta_kind(&self) -> Option<MetaItemKind> {
414 MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
415 }
416}
417
418impl MetaItem {
419 pub fn ident(&self) -> Option<Ident> {
421 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
422 }
423
424 pub fn name(&self) -> Option<Symbol> {
425 self.ident().map(|ident| ident.name)
426 }
427
428 pub fn has_name(&self, name: Symbol) -> bool {
429 self.path == name
430 }
431
432 pub fn is_word(&self) -> bool {
433 #[allow(non_exhaustive_omitted_patterns)] match self.kind {
MetaItemKind::Word => true,
_ => false,
}matches!(self.kind, MetaItemKind::Word)
434 }
435
436 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
437 match &self.kind {
438 MetaItemKind::List(l) => Some(&**l),
439 _ => None,
440 }
441 }
442
443 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
449 match &self.kind {
450 MetaItemKind::NameValue(v) => Some(v),
451 _ => None,
452 }
453 }
454
455 pub fn name_value_literal_span(&self) -> Option<Span> {
463 Some(self.name_value_literal()?.span)
464 }
465
466 pub fn value_str(&self) -> Option<Symbol> {
479 match &self.kind {
480 MetaItemKind::NameValue(v) => v.kind.str(),
481 _ => None,
482 }
483 }
484
485 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
486 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
488 let path = match tt.as_deref() {
489 Some(&TokenTree::Token(
490 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
491 _,
492 )) => 'arm: {
493 let mut segments = if let &token::Ident(name, _) = kind {
494 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
495 iter.peek()
496 {
497 iter.next();
498 {
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))]
499 } else {
500 break 'arm Path::from_ident(Ident::new(name, span));
501 }
502 } else {
503 {
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)]
504 };
505 loop {
506 let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
507 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
508 else {
509 return None;
510 };
511 segments.push(PathSegment::from_ident(Ident::new(name, span)));
512 let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
513 else {
514 break;
515 };
516 iter.next();
517 }
518 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
519 Path { span, segments }
520 }
521 Some(TokenTree::Delimited(
522 _span,
523 _spacing,
524 Delimiter::Invisible(InvisibleOrigin::MetaVar(
525 MetaVarKind::Meta { .. } | MetaVarKind::Path,
526 )),
527 _stream,
528 )) => {
529 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
531 }
532 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
533 {
::core::panicking::panic_fmt(format_args!("Should be `AttrTokenTree::Delimited`, not delim tokens: {0:?}",
tt));
};panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
534 }
535 _ => return None,
536 };
537 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
538 let kind = MetaItemKind::from_tokens(iter)?;
539 let hi = match &kind {
540 MetaItemKind::NameValue(lit) => lit.span.hi(),
541 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
542 _ => path.span.hi(),
543 };
544 let span = path.span.with_hi(hi);
545 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
549 }
550}
551
552impl MetaItemKind {
553 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
555 let mut iter = tokens.iter();
556 let mut result = ThinVec::new();
557 while iter.peek().is_some() {
558 let item = MetaItemInner::from_tokens(&mut iter)?;
559 result.push(item);
560 match iter.next() {
561 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
562 _ => return None,
563 }
564 }
565 Some(result)
566 }
567
568 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
569 match iter.next() {
570 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
571 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
572 }
573 Some(TokenTree::Token(token, _)) => {
574 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
575 }
576 _ => None,
577 }
578 }
579
580 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
581 match iter.peek() {
582 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
583 let inner_tokens = inner_tokens.clone();
584 iter.next();
585 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
586 }
587 Some(TokenTree::Delimited(..)) => None,
588 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
589 iter.next();
590 MetaItemKind::name_value_from_tokens(iter)
591 }
592 _ => Some(MetaItemKind::Word),
593 }
594 }
595
596 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
597 match args {
598 AttrArgs::Empty => Some(MetaItemKind::Word),
599 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
600 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
601 }
602 AttrArgs::Delimited(..) => None,
603 AttrArgs::Eq { expr, .. } => match expr.kind {
604 ExprKind::Lit(token_lit) => {
605 MetaItemLit::from_token_lit(token_lit, expr.span)
607 .ok()
608 .map(|lit| MetaItemKind::NameValue(lit))
609 }
610 _ => None,
611 },
612 }
613 }
614}
615
616impl MetaItemInner {
617 pub fn span(&self) -> Span {
618 match self {
619 MetaItemInner::MetaItem(item) => item.span,
620 MetaItemInner::Lit(lit) => lit.span,
621 }
622 }
623
624 pub fn ident(&self) -> Option<Ident> {
626 self.meta_item().and_then(|meta_item| meta_item.ident())
627 }
628
629 pub fn name(&self) -> Option<Symbol> {
631 self.ident().map(|ident| ident.name)
632 }
633
634 pub fn has_name(&self, name: Symbol) -> bool {
636 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
637 }
638
639 pub fn is_word(&self) -> bool {
641 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
642 }
643
644 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
646 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
647 }
648
649 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
652 self.meta_item().and_then(|meta_item| {
653 meta_item.meta_item_list().and_then(|meta_item_list| {
654 if meta_item_list.len() == 1
655 && let Some(ident) = meta_item.ident()
656 && let Some(lit) = meta_item_list[0].lit()
657 {
658 return Some((ident.name, lit));
659 }
660 None
661 })
662 })
663 }
664
665 pub fn name_value_literal_span(&self) -> Option<Span> {
667 self.meta_item()?.name_value_literal_span()
668 }
669
670 pub fn value_str(&self) -> Option<Symbol> {
673 self.meta_item().and_then(|meta_item| meta_item.value_str())
674 }
675
676 pub fn lit(&self) -> Option<&MetaItemLit> {
678 match self {
679 MetaItemInner::Lit(lit) => Some(lit),
680 _ => None,
681 }
682 }
683
684 pub fn boolean_literal(&self) -> Option<bool> {
686 match self {
687 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
688 _ => None,
689 }
690 }
691
692 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
695 match self {
696 MetaItemInner::MetaItem(_item) => Some(self),
697 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
698 _ => None,
699 }
700 }
701
702 pub fn meta_item(&self) -> Option<&MetaItem> {
704 match self {
705 MetaItemInner::MetaItem(item) => Some(item),
706 _ => None,
707 }
708 }
709
710 pub fn is_meta_item(&self) -> bool {
712 self.meta_item().is_some()
713 }
714
715 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
716 match iter.peek() {
717 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
718 iter.next();
719 return Some(MetaItemInner::Lit(lit));
720 }
721 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
722 iter.next();
723 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
724 }
725 _ => {}
726 }
727 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
728 }
729}
730
731pub fn mk_doc_comment(
732 g: &AttrIdGenerator,
733 comment_kind: CommentKind,
734 style: AttrStyle,
735 data: Symbol,
736 span: Span,
737) -> Attribute {
738 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
739}
740
741pub fn mk_attr_from_item(
742 g: &AttrIdGenerator,
743 item: AttrItem,
744 tokens: Option<LazyAttrTokenStream>,
745 style: AttrStyle,
746 span: Span,
747) -> Attribute {
748 Attribute {
749 kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
750 id: g.mk_attr_id(),
751 style,
752 span,
753 }
754}
755
756fn mk_attr_tokens(
757 style: AttrStyle,
758 unsafety: Safety,
759 item_tokens: AttrTokenStream,
760 span: Span,
761) -> LazyAttrTokenStream {
762 let safety_kw = match unsafety {
763 Safety::Default => None,
764 Safety::Unsafe(span) => Some((kw::Unsafe, span)),
765 Safety::Safe(span) => Some((kw::Safe, span)),
766 };
767 let item_tokens = if let Some((kw, kw_span)) = safety_kw {
768 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![
769 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(kw, kw_span)), Spacing::Alone),
770 AttrTokenTree::Delimited(
771 DelimSpan::from_single(span),
772 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
773 Delimiter::Parenthesis,
774 item_tokens,
775 ),
776 ])
777 } else {
778 item_tokens
779 };
780
781 let mut tokens = match style {
782 AttrStyle::Outer => {
783 ::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)]
784 }
785 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![
786 AttrTokenTree::Token(Token::new(token::Pound, span), Spacing::Joint),
787 AttrTokenTree::Token(Token::new(token::Bang, span), Spacing::JointHidden),
788 ],
789 };
790 tokens.push(AttrTokenTree::Delimited(
791 DelimSpan::from_single(span),
792 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
793 Delimiter::Bracket,
794 item_tokens,
795 ));
796
797 LazyAttrTokenStream::new_direct(AttrTokenStream::new(tokens))
798}
799
800pub fn mk_attr_word(
801 g: &AttrIdGenerator,
802 style: AttrStyle,
803 unsafety: Safety,
804 name: Symbol,
805 span: Span,
806) -> Attribute {
807 let path = Path::from_ident(Ident::new(name, span));
808 let args = AttrArgs::Empty;
809
810 let tokens = Some(mk_attr_tokens(
811 style,
812 unsafety,
813 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(
814 Token::from_ast_ident(Ident::new(name, span)),
815 Spacing::Alone,
816 )]),
817 span,
818 ));
819
820 mk_attr_from_item(
821 g,
822 AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args) },
823 tokens,
824 style,
825 span,
826 )
827}
828
829pub fn mk_attr_nested_word(
830 g: &AttrIdGenerator,
831 style: AttrStyle,
832 unsafety: Safety,
833 outer: Symbol,
834 inner: Symbol,
835 span: Span,
836) -> Attribute {
837 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(
838 Token::from_ast_ident(Ident::new(inner, span)),
839 Spacing::Alone,
840 )]);
841 let outer_ident = Ident::new(outer, span);
842 let path = Path::from_ident(outer_ident);
843 let attr_args = AttrArgs::Delimited(DelimArgs {
844 dspan: DelimSpan::from_single(span),
845 delim: Delimiter::Parenthesis,
846 tokens: inner_tokens,
847 });
848
849 let tokens = Some(mk_attr_tokens(
850 style,
851 unsafety,
852 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![
853 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(outer, span)), Spacing::Alone),
854 AttrTokenTree::Delimited(
855 DelimSpan::from_single(span),
856 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
857 Delimiter::Parenthesis,
858 AttrTokenStream::new(vec![AttrTokenTree::Token(
859 Token::from_ast_ident(Ident::new(inner, span)),
860 Spacing::Alone,
861 )]),
862 ),
863 ]),
864 span,
865 ));
866
867 mk_attr_from_item(
868 g,
869 AttrItem { unsafety, path, args: AttrItemKind::Unparsed(attr_args) },
870 tokens,
871 style,
872 span,
873 )
874}
875
876pub fn mk_attr_name_value_str(
877 g: &AttrIdGenerator,
878 style: AttrStyle,
879 unsafety: Safety,
880 name: Symbol,
881 val: Symbol,
882 span: Span,
883) -> Attribute {
884 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
885 let expr = Box::new(Expr {
886 id: DUMMY_NODE_ID,
887 kind: ExprKind::Lit(lit),
888 span,
889 attrs: AttrVec::new(),
890 tokens: None,
891 });
892 let path = Path::from_ident(Ident::new(name, span));
893 let args = AttrArgs::Eq { eq_span: span, expr };
894
895 let tokens = Some(mk_attr_tokens(
896 style,
897 unsafety,
898 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![
899 AttrTokenTree::Token(Token::from_ast_ident(Ident::new(name, span)), Spacing::Alone),
900 AttrTokenTree::Token(Token::new(token::Eq, span), Spacing::Alone),
901 AttrTokenTree::Token(
902 Token::new(token::TokenKind::lit(lit.kind, lit.symbol, lit.suffix), span),
903 Spacing::Alone,
904 ),
905 ]),
906 span,
907 ));
908
909 mk_attr_from_item(
910 g,
911 AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args) },
912 tokens,
913 style,
914 span,
915 )
916}
917
918pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
919 attrs.iter().filter(move |attr| attr.has_name(name))
920}
921
922pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
923 filter_by_name(attrs, name).next()
924}
925
926pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
927 find_by_name(attrs, name).and_then(|attr| attr.value_str())
928}
929
930pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
931 find_by_name(attrs, name).is_some()
932}
933
934pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
935 items.iter().any(|item| item.has_name(name))
936}
937
938impl MetaItemLit {
939 pub fn value_as_str(&self) -> Option<Symbol> {
940 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
941 }
942}
943
944pub trait AttributeExt: Debug {
945 fn id(&self) -> AttrId;
946
947 fn name(&self) -> Option<Symbol>;
950
951 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
953
954 fn value_str(&self) -> Option<Symbol>;
956
957 fn value_span(&self) -> Option<Span>;
959
960 fn path_matches(&self, name: &[Symbol]) -> bool;
964
965 fn is_doc_comment(&self) -> Option<Span>;
969
970 #[inline]
973 fn has_name(&self, name: Symbol) -> bool {
974 self.name().map(|x| x == name).unwrap_or(false)
975 }
976
977 #[inline]
980 fn has_any_name(&self, names: &[Symbol]) -> bool {
981 names.iter().any(|&name| self.has_name(name))
982 }
983
984 fn span(&self) -> Span;
986
987 fn is_word(&self) -> bool;
989
990 fn path(&self) -> SmallVec<[Symbol; 1]> {
991 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])
992 }
993
994 fn path_span(&self) -> Option<Span>;
995
996 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
998
999 fn doc_str(&self) -> Option<Symbol>;
1004
1005 fn is_proc_macro_attr(&self) -> bool {
1008 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
1009 .iter()
1010 .any(|kind| self.has_name(*kind))
1011 }
1012 fn is_automatically_derived_attr(&self) -> bool;
1014
1015 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
1021
1022 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
1030
1031 fn is_doc_hidden(&self) -> bool;
1033
1034 fn is_doc_keyword_or_attribute(&self) -> bool;
1036
1037 fn is_rustc_doc_primitive(&self) -> bool;
1039}
1040
1041impl Attribute {
1044 pub fn id(&self) -> AttrId {
1045 AttributeExt::id(self)
1046 }
1047
1048 pub fn name(&self) -> Option<Symbol> {
1049 AttributeExt::name(self)
1050 }
1051
1052 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
1053 AttributeExt::meta_item_list(self)
1054 }
1055
1056 pub fn value_str(&self) -> Option<Symbol> {
1057 AttributeExt::value_str(self)
1058 }
1059
1060 pub fn value_span(&self) -> Option<Span> {
1061 AttributeExt::value_span(self)
1062 }
1063
1064 pub fn path_matches(&self, name: &[Symbol]) -> bool {
1065 AttributeExt::path_matches(self, name)
1066 }
1067
1068 pub fn is_doc_comment(&self) -> bool {
1070 AttributeExt::is_doc_comment(self).is_some()
1071 }
1072
1073 #[inline]
1074 pub fn has_name(&self, name: Symbol) -> bool {
1075 AttributeExt::has_name(self, name)
1076 }
1077
1078 #[inline]
1079 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
1080 AttributeExt::has_any_name(self, names)
1081 }
1082
1083 pub fn span(&self) -> Span {
1084 AttributeExt::span(self)
1085 }
1086
1087 pub fn is_word(&self) -> bool {
1088 AttributeExt::is_word(self)
1089 }
1090
1091 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
1092 AttributeExt::path(self)
1093 }
1094
1095 pub fn doc_str(&self) -> Option<Symbol> {
1096 AttributeExt::doc_str(self)
1097 }
1098
1099 pub fn is_proc_macro_attr(&self) -> bool {
1100 AttributeExt::is_proc_macro_attr(self)
1101 }
1102
1103 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
1104 AttributeExt::doc_str_and_fragment_kind(self)
1105 }
1106}