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::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 DelimSpan, LazyAttrTokenStream, Spacing, 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::DocComment(..) => { ::core::panicking::panic_fmt(format_args!("unexpected doc comment")); }panic!("unexpected doc comment"),
66 }
67 }
68
69 pub fn replace_args(&mut self, new_args: AttrItemKind) {
72 match &mut self.kind {
73 AttrKind::Normal(normal) => normal.item.args = new_args,
74 AttrKind::DocComment(..) => { ::core::panicking::panic_fmt(format_args!("unexpected doc comment")); }panic!("unexpected doc comment"),
75 }
76 }
77
78 pub fn unwrap_normal_item(self) -> AttrItem {
79 match self.kind {
80 AttrKind::Normal(normal) => normal.item,
81 AttrKind::DocComment(..) => { ::core::panicking::panic_fmt(format_args!("unexpected doc comment")); }panic!("unexpected doc comment"),
82 }
83 }
84}
85
86impl AttributeExt for Attribute {
87 fn id(&self) -> AttrId {
88 self.id
89 }
90
91 fn value_span(&self) -> Option<Span> {
92 match &self.kind {
93 AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
94 AttrArgs::Eq { expr, .. } => Some(expr.span),
95 _ => None,
96 },
97 AttrKind::DocComment(..) => None,
98 }
99 }
100
101 fn is_doc_comment(&self) -> Option<Span> {
105 match self.kind {
106 AttrKind::Normal(..) => None,
107 AttrKind::DocComment(..) => Some(self.span),
108 }
109 }
110
111 fn name(&self) -> Option<Symbol> {
113 match &self.kind {
114 AttrKind::Normal(normal) => {
115 if let [ident] = &*normal.item.path.segments {
116 Some(ident.ident.name)
117 } else {
118 None
119 }
120 }
121 AttrKind::DocComment(..) => None,
122 }
123 }
124
125 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
126 match &self.kind {
127 AttrKind::Normal(p) => {
128 Some(p.item.path.segments.iter().map(|i| i.ident.name).collect())
129 }
130 AttrKind::DocComment(_, _) => None,
131 }
132 }
133
134 fn path_span(&self) -> Option<Span> {
135 match &self.kind {
136 AttrKind::Normal(attr) => Some(attr.item.path.span),
137 AttrKind::DocComment(_, _) => None,
138 }
139 }
140
141 fn path_matches(&self, name: &[Symbol]) -> bool {
142 match &self.kind {
143 AttrKind::Normal(normal) => {
144 normal.item.path.segments.len() == name.len()
145 && normal
146 .item
147 .path
148 .segments
149 .iter()
150 .zip(name)
151 .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
152 }
153 AttrKind::DocComment(..) => false,
154 }
155 }
156
157 fn span(&self) -> Span {
158 self.span
159 }
160
161 fn is_word(&self) -> bool {
162 if let AttrKind::Normal(normal) = &self.kind {
163 #[allow(non_exhaustive_omitted_patterns)] match normal.item.args {
AttrItemKind::Unparsed(AttrArgs::Empty) => true,
_ => false,
}matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
164 } else {
165 false
166 }
167 }
168
169 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
177 match &self.kind {
178 AttrKind::Normal(normal) => normal.item.meta_item_list(),
179 AttrKind::DocComment(..) => None,
180 }
181 }
182
183 fn value_str(&self) -> Option<Symbol> {
199 match &self.kind {
200 AttrKind::Normal(normal) => normal.item.value_str(),
201 AttrKind::DocComment(..) => None,
202 }
203 }
204
205 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
211 match &self.kind {
212 AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))),
213 AttrKind::Normal(normal) if normal.item.path == sym::doc => {
214 if let Some(value) = normal.item.value_str()
215 && let Some(value_span) = normal.item.value_span()
216 {
217 Some((value, DocFragmentKind::Raw(value_span)))
218 } else {
219 None
220 }
221 }
222 _ => None,
223 }
224 }
225
226 fn doc_str(&self) -> Option<Symbol> {
231 match &self.kind {
232 AttrKind::DocComment(.., data) => Some(*data),
233 AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
234 _ => None,
235 }
236 }
237
238 fn deprecation_note(&self) -> Option<Ident> {
239 match &self.kind {
240 AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
241 let meta = &normal.item;
242
243 if let Some(s) = meta.value_str() {
245 return Some(Ident { name: s, span: meta.span() });
246 }
247
248 if let Some(list) = meta.meta_item_list() {
250 for nested in list {
251 if let Some(mi) = nested.meta_item()
252 && mi.path == sym::note
253 && let Some(s) = mi.value_str()
254 {
255 return Some(Ident { name: s, span: mi.span });
256 }
257 }
258 }
259
260 None
261 }
262 _ => None,
263 }
264 }
265
266 fn doc_resolution_scope(&self) -> Option<AttrStyle> {
267 match &self.kind {
268 AttrKind::DocComment(..) => Some(self.style),
269 AttrKind::Normal(normal)
270 if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
271 {
272 Some(self.style)
273 }
274 _ => None,
275 }
276 }
277
278 fn is_automatically_derived_attr(&self) -> bool {
279 self.has_name(sym::automatically_derived)
280 }
281
282 fn is_doc_hidden(&self) -> bool {
283 self.has_name(sym::doc)
284 && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden))
285 }
286
287 fn is_doc_keyword_or_attribute(&self) -> bool {
288 if self.has_name(sym::doc)
289 && let Some(items) = self.meta_item_list()
290 {
291 for item in items {
292 if item.has_name(sym::keyword) || item.has_name(sym::attribute) {
293 return true;
294 }
295 }
296 }
297 false
298 }
299
300 fn is_rustc_doc_primitive(&self) -> bool {
301 self.has_name(sym::rustc_doc_primitive)
302 }
303}
304
305impl Attribute {
306 pub fn style(&self) -> AttrStyle {
307 self.style
308 }
309
310 pub fn may_have_doc_links(&self) -> bool {
311 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
312 || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
313 }
314
315 pub fn meta(&self) -> Option<MetaItem> {
317 match &self.kind {
318 AttrKind::Normal(normal) => normal.item.meta(self.span),
319 AttrKind::DocComment(..) => None,
320 }
321 }
322
323 pub fn meta_kind(&self) -> Option<MetaItemKind> {
324 match &self.kind {
325 AttrKind::Normal(normal) => normal.item.meta_kind(),
326 AttrKind::DocComment(..) => None,
327 }
328 }
329
330 pub fn token_trees(&self) -> Vec<TokenTree> {
331 match self.kind {
332 AttrKind::Normal(ref normal) => normal
333 .tokens
334 .as_ref()
335 .unwrap_or_else(|| {
::core::panicking::panic_fmt(format_args!("attribute is missing tokens: {0:?}",
self));
}panic!("attribute is missing tokens: {self:?}"))
336 .to_attr_token_stream()
337 .to_token_trees(),
338 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(
339 token::DocComment(comment_kind, self.style, data),
340 self.span,
341 )],
342 }
343 }
344}
345
346impl AttrItem {
347 pub fn span(&self) -> Span {
348 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
349 }
350
351 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
352 match &self.args.unparsed_ref()? {
353 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
354 MetaItemKind::list_from_tokens(args.tokens.clone())
355 }
356 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
357 }
358 }
359
360 fn value_str(&self) -> Option<Symbol> {
373 match &self.args.unparsed_ref()? {
374 AttrArgs::Eq { expr, .. } => match expr.kind {
375 ExprKind::Lit(token_lit) => {
376 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
377 }
378 _ => None,
379 },
380 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
381 }
382 }
383
384 fn value_span(&self) -> Option<Span> {
397 match &self.args.unparsed_ref()? {
398 AttrArgs::Eq { expr, .. } => Some(expr.span),
399 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
400 }
401 }
402
403 pub fn meta(&self, span: Span) -> Option<MetaItem> {
404 Some(MetaItem {
405 unsafety: Safety::Default,
406 path: self.path.clone(),
407 kind: self.meta_kind()?,
408 span,
409 })
410 }
411
412 pub fn meta_kind(&self) -> Option<MetaItemKind> {
413 MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
414 }
415}
416
417impl MetaItem {
418 pub fn ident(&self) -> Option<Ident> {
420 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
421 }
422
423 pub fn name(&self) -> Option<Symbol> {
424 self.ident().map(|ident| ident.name)
425 }
426
427 pub fn has_name(&self, name: Symbol) -> bool {
428 self.path == name
429 }
430
431 pub fn is_word(&self) -> bool {
432 #[allow(non_exhaustive_omitted_patterns)] match self.kind {
MetaItemKind::Word => true,
_ => false,
}matches!(self.kind, MetaItemKind::Word)
433 }
434
435 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
436 match &self.kind {
437 MetaItemKind::List(l) => Some(&**l),
438 _ => None,
439 }
440 }
441
442 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
448 match &self.kind {
449 MetaItemKind::NameValue(v) => Some(v),
450 _ => None,
451 }
452 }
453
454 pub fn name_value_literal_span(&self) -> Option<Span> {
462 Some(self.name_value_literal()?.span)
463 }
464
465 pub fn value_str(&self) -> Option<Symbol> {
478 match &self.kind {
479 MetaItemKind::NameValue(v) => v.kind.str(),
480 _ => None,
481 }
482 }
483
484 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
485 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
487 let path = match tt.as_deref() {
488 Some(&TokenTree::Token(
489 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
490 _,
491 )) => 'arm: {
492 let mut segments = if let &token::Ident(name, _) = kind {
493 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
494 iter.peek()
495 {
496 iter.next();
497 {
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))]
498 } else {
499 break 'arm Path::from_ident(Ident::new(name, span));
500 }
501 } else {
502 {
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)]
503 };
504 loop {
505 let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
506 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
507 else {
508 return None;
509 };
510 segments.push(PathSegment::from_ident(Ident::new(name, span)));
511 let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
512 else {
513 break;
514 };
515 iter.next();
516 }
517 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
518 Path { span, segments, tokens: None }
519 }
520 Some(TokenTree::Delimited(
521 _span,
522 _spacing,
523 Delimiter::Invisible(InvisibleOrigin::MetaVar(
524 MetaVarKind::Meta { .. } | MetaVarKind::Path,
525 )),
526 _stream,
527 )) => {
528 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
530 }
531 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
532 {
::core::panicking::panic_fmt(format_args!("Should be `AttrTokenTree::Delimited`, not delim tokens: {0:?}",
tt));
};panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
533 }
534 _ => return None,
535 };
536 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
537 let kind = MetaItemKind::from_tokens(iter)?;
538 let hi = match &kind {
539 MetaItemKind::NameValue(lit) => lit.span.hi(),
540 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
541 _ => path.span.hi(),
542 };
543 let span = path.span.with_hi(hi);
544 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
548 }
549}
550
551impl MetaItemKind {
552 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
554 let mut iter = tokens.iter();
555 let mut result = ThinVec::new();
556 while iter.peek().is_some() {
557 let item = MetaItemInner::from_tokens(&mut iter)?;
558 result.push(item);
559 match iter.next() {
560 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
561 _ => return None,
562 }
563 }
564 Some(result)
565 }
566
567 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
568 match iter.next() {
569 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
570 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
571 }
572 Some(TokenTree::Token(token, _)) => {
573 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
574 }
575 _ => None,
576 }
577 }
578
579 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
580 match iter.peek() {
581 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
582 let inner_tokens = inner_tokens.clone();
583 iter.next();
584 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
585 }
586 Some(TokenTree::Delimited(..)) => None,
587 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
588 iter.next();
589 MetaItemKind::name_value_from_tokens(iter)
590 }
591 _ => Some(MetaItemKind::Word),
592 }
593 }
594
595 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
596 match args {
597 AttrArgs::Empty => Some(MetaItemKind::Word),
598 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
599 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
600 }
601 AttrArgs::Delimited(..) => None,
602 AttrArgs::Eq { expr, .. } => match expr.kind {
603 ExprKind::Lit(token_lit) => {
604 MetaItemLit::from_token_lit(token_lit, expr.span)
606 .ok()
607 .map(|lit| MetaItemKind::NameValue(lit))
608 }
609 _ => None,
610 },
611 }
612 }
613}
614
615impl MetaItemInner {
616 pub fn span(&self) -> Span {
617 match self {
618 MetaItemInner::MetaItem(item) => item.span,
619 MetaItemInner::Lit(lit) => lit.span,
620 }
621 }
622
623 pub fn ident(&self) -> Option<Ident> {
625 self.meta_item().and_then(|meta_item| meta_item.ident())
626 }
627
628 pub fn name(&self) -> Option<Symbol> {
630 self.ident().map(|ident| ident.name)
631 }
632
633 pub fn has_name(&self, name: Symbol) -> bool {
635 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
636 }
637
638 pub fn is_word(&self) -> bool {
640 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
641 }
642
643 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
645 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
646 }
647
648 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
651 self.meta_item().and_then(|meta_item| {
652 meta_item.meta_item_list().and_then(|meta_item_list| {
653 if meta_item_list.len() == 1
654 && let Some(ident) = meta_item.ident()
655 && let Some(lit) = meta_item_list[0].lit()
656 {
657 return Some((ident.name, lit));
658 }
659 None
660 })
661 })
662 }
663
664 pub fn name_value_literal_span(&self) -> Option<Span> {
666 self.meta_item()?.name_value_literal_span()
667 }
668
669 pub fn value_str(&self) -> Option<Symbol> {
672 self.meta_item().and_then(|meta_item| meta_item.value_str())
673 }
674
675 pub fn lit(&self) -> Option<&MetaItemLit> {
677 match self {
678 MetaItemInner::Lit(lit) => Some(lit),
679 _ => None,
680 }
681 }
682
683 pub fn boolean_literal(&self) -> Option<bool> {
685 match self {
686 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
687 _ => None,
688 }
689 }
690
691 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
694 match self {
695 MetaItemInner::MetaItem(_item) => Some(self),
696 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
697 _ => None,
698 }
699 }
700
701 pub fn meta_item(&self) -> Option<&MetaItem> {
703 match self {
704 MetaItemInner::MetaItem(item) => Some(item),
705 _ => None,
706 }
707 }
708
709 pub fn is_meta_item(&self) -> bool {
711 self.meta_item().is_some()
712 }
713
714 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
715 match iter.peek() {
716 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
717 iter.next();
718 return Some(MetaItemInner::Lit(lit));
719 }
720 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
721 iter.next();
722 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
723 }
724 _ => {}
725 }
726 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
727 }
728}
729
730pub fn mk_doc_comment(
731 g: &AttrIdGenerator,
732 comment_kind: CommentKind,
733 style: AttrStyle,
734 data: Symbol,
735 span: Span,
736) -> Attribute {
737 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
738}
739
740fn mk_attr(
741 g: &AttrIdGenerator,
742 style: AttrStyle,
743 unsafety: Safety,
744 path: Path,
745 args: AttrArgs,
746 span: Span,
747) -> Attribute {
748 mk_attr_from_item(
749 g,
750 AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
751 None,
752 style,
753 span,
754 )
755}
756
757pub fn mk_attr_from_item(
758 g: &AttrIdGenerator,
759 item: AttrItem,
760 tokens: Option<LazyAttrTokenStream>,
761 style: AttrStyle,
762 span: Span,
763) -> Attribute {
764 Attribute {
765 kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
766 id: g.mk_attr_id(),
767 style,
768 span,
769 }
770}
771
772pub fn mk_attr_word(
773 g: &AttrIdGenerator,
774 style: AttrStyle,
775 unsafety: Safety,
776 name: Symbol,
777 span: Span,
778) -> Attribute {
779 let path = Path::from_ident(Ident::new(name, span));
780 let args = AttrArgs::Empty;
781 mk_attr(g, style, unsafety, path, args, span)
782}
783
784pub fn mk_attr_nested_word(
785 g: &AttrIdGenerator,
786 style: AttrStyle,
787 unsafety: Safety,
788 outer: Symbol,
789 inner: Symbol,
790 span: Span,
791) -> Attribute {
792 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(
793 Token::from_ast_ident(Ident::new(inner, span)),
794 Spacing::Alone,
795 )]);
796 let outer_ident = Ident::new(outer, span);
797 let path = Path::from_ident(outer_ident);
798 let attr_args = AttrArgs::Delimited(DelimArgs {
799 dspan: DelimSpan::from_single(span),
800 delim: Delimiter::Parenthesis,
801 tokens: inner_tokens,
802 });
803 mk_attr(g, style, unsafety, path, attr_args, span)
804}
805
806pub fn mk_attr_name_value_str(
807 g: &AttrIdGenerator,
808 style: AttrStyle,
809 unsafety: Safety,
810 name: Symbol,
811 val: Symbol,
812 span: Span,
813) -> Attribute {
814 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
815 let expr = Box::new(Expr {
816 id: DUMMY_NODE_ID,
817 kind: ExprKind::Lit(lit),
818 span,
819 attrs: AttrVec::new(),
820 tokens: None,
821 });
822 let path = Path::from_ident(Ident::new(name, span));
823 let args = AttrArgs::Eq { eq_span: span, expr };
824 mk_attr(g, style, unsafety, path, args, span)
825}
826
827pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
828 attrs.iter().filter(move |attr| attr.has_name(name))
829}
830
831pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
832 filter_by_name(attrs, name).next()
833}
834
835pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
836 find_by_name(attrs, name).and_then(|attr| attr.value_str())
837}
838
839pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
840 find_by_name(attrs, name).is_some()
841}
842
843pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
844 items.iter().any(|item| item.has_name(name))
845}
846
847impl MetaItemLit {
848 pub fn value_str(&self) -> Option<Symbol> {
849 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
850 }
851}
852
853pub trait AttributeExt: Debug {
854 fn id(&self) -> AttrId;
855
856 fn name(&self) -> Option<Symbol>;
859
860 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
862
863 fn value_str(&self) -> Option<Symbol>;
865
866 fn value_span(&self) -> Option<Span>;
868
869 fn path_matches(&self, name: &[Symbol]) -> bool;
873
874 fn is_doc_comment(&self) -> Option<Span>;
878
879 #[inline]
880 fn has_name(&self, name: Symbol) -> bool {
881 self.name().map(|x| x == name).unwrap_or(false)
882 }
883
884 #[inline]
885 fn has_any_name(&self, names: &[Symbol]) -> bool {
886 names.iter().any(|&name| self.has_name(name))
887 }
888
889 fn span(&self) -> Span;
891
892 fn is_word(&self) -> bool;
893
894 fn path(&self) -> SmallVec<[Symbol; 1]> {
895 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])
896 }
897
898 fn path_span(&self) -> Option<Span>;
899
900 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
902
903 fn doc_str(&self) -> Option<Symbol>;
908
909 fn deprecation_note(&self) -> Option<Ident>;
913
914 fn is_proc_macro_attr(&self) -> bool {
915 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
916 .iter()
917 .any(|kind| self.has_name(*kind))
918 }
919 fn is_automatically_derived_attr(&self) -> bool;
920
921 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
927
928 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
936
937 fn is_doc_hidden(&self) -> bool;
939
940 fn is_doc_keyword_or_attribute(&self) -> bool;
942
943 fn is_rustc_doc_primitive(&self) -> bool;
945}
946
947impl Attribute {
950 pub fn id(&self) -> AttrId {
951 AttributeExt::id(self)
952 }
953
954 pub fn name(&self) -> Option<Symbol> {
955 AttributeExt::name(self)
956 }
957
958 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
959 AttributeExt::meta_item_list(self)
960 }
961
962 pub fn value_str(&self) -> Option<Symbol> {
963 AttributeExt::value_str(self)
964 }
965
966 pub fn value_span(&self) -> Option<Span> {
967 AttributeExt::value_span(self)
968 }
969
970 pub fn path_matches(&self, name: &[Symbol]) -> bool {
971 AttributeExt::path_matches(self, name)
972 }
973
974 pub fn is_doc_comment(&self) -> bool {
976 AttributeExt::is_doc_comment(self).is_some()
977 }
978
979 #[inline]
980 pub fn has_name(&self, name: Symbol) -> bool {
981 AttributeExt::has_name(self, name)
982 }
983
984 #[inline]
985 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
986 AttributeExt::has_any_name(self, names)
987 }
988
989 pub fn span(&self) -> Span {
990 AttributeExt::span(self)
991 }
992
993 pub fn is_word(&self) -> bool {
994 AttributeExt::is_word(self)
995 }
996
997 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
998 AttributeExt::path(self)
999 }
1000
1001 pub fn doc_str(&self) -> Option<Symbol> {
1002 AttributeExt::doc_str(self)
1003 }
1004
1005 pub fn is_proc_macro_attr(&self) -> bool {
1006 AttributeExt::is_proc_macro_attr(self)
1007 }
1008
1009 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
1010 AttributeExt::doc_str_and_fragment_kind(self)
1011 }
1012}