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 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(..) => 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(..) => 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(..) => 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 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<Symbol> {
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(s);
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(s);
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
301impl Attribute {
302 pub fn style(&self) -> AttrStyle {
303 self.style
304 }
305
306 pub fn may_have_doc_links(&self) -> bool {
307 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
308 || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
309 }
310
311 pub fn meta(&self) -> Option<MetaItem> {
313 match &self.kind {
314 AttrKind::Normal(normal) => normal.item.meta(self.span),
315 AttrKind::DocComment(..) => None,
316 }
317 }
318
319 pub fn meta_kind(&self) -> Option<MetaItemKind> {
320 match &self.kind {
321 AttrKind::Normal(normal) => normal.item.meta_kind(),
322 AttrKind::DocComment(..) => None,
323 }
324 }
325
326 pub fn token_trees(&self) -> Vec<TokenTree> {
327 match self.kind {
328 AttrKind::Normal(ref normal) => normal
329 .tokens
330 .as_ref()
331 .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
332 .to_attr_token_stream()
333 .to_token_trees(),
334 AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone(
335 token::DocComment(comment_kind, self.style, data),
336 self.span,
337 )],
338 }
339 }
340}
341
342impl AttrItem {
343 pub fn span(&self) -> Span {
344 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
345 }
346
347 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
348 match &self.args.unparsed_ref()? {
349 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
350 MetaItemKind::list_from_tokens(args.tokens.clone())
351 }
352 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
353 }
354 }
355
356 fn value_str(&self) -> Option<Symbol> {
369 match &self.args.unparsed_ref()? {
370 AttrArgs::Eq { expr, .. } => match expr.kind {
371 ExprKind::Lit(token_lit) => {
372 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
373 }
374 _ => None,
375 },
376 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
377 }
378 }
379
380 fn value_span(&self) -> Option<Span> {
393 match &self.args.unparsed_ref()? {
394 AttrArgs::Eq { expr, .. } => Some(expr.span),
395 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
396 }
397 }
398
399 pub fn meta(&self, span: Span) -> Option<MetaItem> {
400 Some(MetaItem {
401 unsafety: Safety::Default,
402 path: self.path.clone(),
403 kind: self.meta_kind()?,
404 span,
405 })
406 }
407
408 pub fn meta_kind(&self) -> Option<MetaItemKind> {
409 MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
410 }
411}
412
413impl MetaItem {
414 pub fn ident(&self) -> Option<Ident> {
416 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
417 }
418
419 pub fn name(&self) -> Option<Symbol> {
420 self.ident().map(|ident| ident.name)
421 }
422
423 pub fn has_name(&self, name: Symbol) -> bool {
424 self.path == name
425 }
426
427 pub fn is_word(&self) -> bool {
428 matches!(self.kind, MetaItemKind::Word)
429 }
430
431 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
432 match &self.kind {
433 MetaItemKind::List(l) => Some(&**l),
434 _ => None,
435 }
436 }
437
438 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
444 match &self.kind {
445 MetaItemKind::NameValue(v) => Some(v),
446 _ => None,
447 }
448 }
449
450 pub fn name_value_literal_span(&self) -> Option<Span> {
458 Some(self.name_value_literal()?.span)
459 }
460
461 pub fn value_str(&self) -> Option<Symbol> {
474 match &self.kind {
475 MetaItemKind::NameValue(v) => v.kind.str(),
476 _ => None,
477 }
478 }
479
480 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
481 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
483 let path = match tt.as_deref() {
484 Some(&TokenTree::Token(
485 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
486 _,
487 )) => 'arm: {
488 let mut segments = if let &token::Ident(name, _) = kind {
489 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
490 iter.peek()
491 {
492 iter.next();
493 thin_vec![PathSegment::from_ident(Ident::new(name, span))]
494 } else {
495 break 'arm Path::from_ident(Ident::new(name, span));
496 }
497 } else {
498 thin_vec![PathSegment::path_root(span)]
499 };
500 loop {
501 let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
502 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
503 else {
504 return None;
505 };
506 segments.push(PathSegment::from_ident(Ident::new(name, span)));
507 let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
508 else {
509 break;
510 };
511 iter.next();
512 }
513 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
514 Path { span, segments, tokens: None }
515 }
516 Some(TokenTree::Delimited(
517 _span,
518 _spacing,
519 Delimiter::Invisible(InvisibleOrigin::MetaVar(
520 MetaVarKind::Meta { .. } | MetaVarKind::Path,
521 )),
522 _stream,
523 )) => {
524 unreachable!()
526 }
527 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
528 panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
529 }
530 _ => return None,
531 };
532 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
533 let kind = MetaItemKind::from_tokens(iter)?;
534 let hi = match &kind {
535 MetaItemKind::NameValue(lit) => lit.span.hi(),
536 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
537 _ => path.span.hi(),
538 };
539 let span = path.span.with_hi(hi);
540 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
544 }
545}
546
547impl MetaItemKind {
548 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
550 let mut iter = tokens.iter();
551 let mut result = ThinVec::new();
552 while iter.peek().is_some() {
553 let item = MetaItemInner::from_tokens(&mut iter)?;
554 result.push(item);
555 match iter.next() {
556 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
557 _ => return None,
558 }
559 }
560 Some(result)
561 }
562
563 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
564 match iter.next() {
565 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
566 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
567 }
568 Some(TokenTree::Token(token, _)) => {
569 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
570 }
571 _ => None,
572 }
573 }
574
575 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
576 match iter.peek() {
577 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
578 let inner_tokens = inner_tokens.clone();
579 iter.next();
580 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
581 }
582 Some(TokenTree::Delimited(..)) => None,
583 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
584 iter.next();
585 MetaItemKind::name_value_from_tokens(iter)
586 }
587 _ => Some(MetaItemKind::Word),
588 }
589 }
590
591 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
592 match args {
593 AttrArgs::Empty => Some(MetaItemKind::Word),
594 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
595 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
596 }
597 AttrArgs::Delimited(..) => None,
598 AttrArgs::Eq { expr, .. } => match expr.kind {
599 ExprKind::Lit(token_lit) => {
600 MetaItemLit::from_token_lit(token_lit, expr.span)
602 .ok()
603 .map(|lit| MetaItemKind::NameValue(lit))
604 }
605 _ => None,
606 },
607 }
608 }
609}
610
611impl MetaItemInner {
612 pub fn span(&self) -> Span {
613 match self {
614 MetaItemInner::MetaItem(item) => item.span,
615 MetaItemInner::Lit(lit) => lit.span,
616 }
617 }
618
619 pub fn ident(&self) -> Option<Ident> {
621 self.meta_item().and_then(|meta_item| meta_item.ident())
622 }
623
624 pub fn name(&self) -> Option<Symbol> {
626 self.ident().map(|ident| ident.name)
627 }
628
629 pub fn has_name(&self, name: Symbol) -> bool {
631 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
632 }
633
634 pub fn is_word(&self) -> bool {
636 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
637 }
638
639 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
641 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
642 }
643
644 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
647 self.meta_item().and_then(|meta_item| {
648 meta_item.meta_item_list().and_then(|meta_item_list| {
649 if meta_item_list.len() == 1
650 && let Some(ident) = meta_item.ident()
651 && let Some(lit) = meta_item_list[0].lit()
652 {
653 return Some((ident.name, lit));
654 }
655 None
656 })
657 })
658 }
659
660 pub fn name_value_literal_span(&self) -> Option<Span> {
662 self.meta_item()?.name_value_literal_span()
663 }
664
665 pub fn value_str(&self) -> Option<Symbol> {
668 self.meta_item().and_then(|meta_item| meta_item.value_str())
669 }
670
671 pub fn lit(&self) -> Option<&MetaItemLit> {
673 match self {
674 MetaItemInner::Lit(lit) => Some(lit),
675 _ => None,
676 }
677 }
678
679 pub fn boolean_literal(&self) -> Option<bool> {
681 match self {
682 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
683 _ => None,
684 }
685 }
686
687 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
690 match self {
691 MetaItemInner::MetaItem(_item) => Some(self),
692 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
693 _ => None,
694 }
695 }
696
697 pub fn meta_item(&self) -> Option<&MetaItem> {
699 match self {
700 MetaItemInner::MetaItem(item) => Some(item),
701 _ => None,
702 }
703 }
704
705 pub fn is_meta_item(&self) -> bool {
707 self.meta_item().is_some()
708 }
709
710 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
711 match iter.peek() {
712 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
713 iter.next();
714 return Some(MetaItemInner::Lit(lit));
715 }
716 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
717 iter.next();
718 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
719 }
720 _ => {}
721 }
722 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
723 }
724}
725
726pub fn mk_doc_comment(
727 g: &AttrIdGenerator,
728 comment_kind: CommentKind,
729 style: AttrStyle,
730 data: Symbol,
731 span: Span,
732) -> Attribute {
733 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
734}
735
736fn mk_attr(
737 g: &AttrIdGenerator,
738 style: AttrStyle,
739 unsafety: Safety,
740 path: Path,
741 args: AttrArgs,
742 span: Span,
743) -> Attribute {
744 mk_attr_from_item(
745 g,
746 AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
747 None,
748 style,
749 span,
750 )
751}
752
753pub fn mk_attr_from_item(
754 g: &AttrIdGenerator,
755 item: AttrItem,
756 tokens: Option<LazyAttrTokenStream>,
757 style: AttrStyle,
758 span: Span,
759) -> Attribute {
760 Attribute {
761 kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
762 id: g.mk_attr_id(),
763 style,
764 span,
765 }
766}
767
768pub fn mk_attr_word(
769 g: &AttrIdGenerator,
770 style: AttrStyle,
771 unsafety: Safety,
772 name: Symbol,
773 span: Span,
774) -> Attribute {
775 let path = Path::from_ident(Ident::new(name, span));
776 let args = AttrArgs::Empty;
777 mk_attr(g, style, unsafety, path, args, span)
778}
779
780pub fn mk_attr_nested_word(
781 g: &AttrIdGenerator,
782 style: AttrStyle,
783 unsafety: Safety,
784 outer: Symbol,
785 inner: Symbol,
786 span: Span,
787) -> Attribute {
788 let inner_tokens = TokenStream::new(vec![TokenTree::Token(
789 Token::from_ast_ident(Ident::new(inner, span)),
790 Spacing::Alone,
791 )]);
792 let outer_ident = Ident::new(outer, span);
793 let path = Path::from_ident(outer_ident);
794 let attr_args = AttrArgs::Delimited(DelimArgs {
795 dspan: DelimSpan::from_single(span),
796 delim: Delimiter::Parenthesis,
797 tokens: inner_tokens,
798 });
799 mk_attr(g, style, unsafety, path, attr_args, span)
800}
801
802pub fn mk_attr_name_value_str(
803 g: &AttrIdGenerator,
804 style: AttrStyle,
805 unsafety: Safety,
806 name: Symbol,
807 val: Symbol,
808 span: Span,
809) -> Attribute {
810 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
811 let expr = Box::new(Expr {
812 id: DUMMY_NODE_ID,
813 kind: ExprKind::Lit(lit),
814 span,
815 attrs: AttrVec::new(),
816 tokens: None,
817 });
818 let path = Path::from_ident(Ident::new(name, span));
819 let args = AttrArgs::Eq { eq_span: span, expr };
820 mk_attr(g, style, unsafety, path, args, span)
821}
822
823pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
824 attrs.iter().filter(move |attr| attr.has_name(name))
825}
826
827pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
828 filter_by_name(attrs, name).next()
829}
830
831pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
832 find_by_name(attrs, name).and_then(|attr| attr.value_str())
833}
834
835pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
836 find_by_name(attrs, name).is_some()
837}
838
839pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
840 items.iter().any(|item| item.has_name(name))
841}
842
843impl MetaItemLit {
844 pub fn value_str(&self) -> Option<Symbol> {
845 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
846 }
847}
848
849pub trait AttributeExt: Debug {
850 fn id(&self) -> AttrId;
851
852 fn name(&self) -> Option<Symbol>;
855
856 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
858
859 fn value_str(&self) -> Option<Symbol>;
861
862 fn value_span(&self) -> Option<Span>;
864
865 fn path_matches(&self, name: &[Symbol]) -> bool;
869
870 fn is_doc_comment(&self) -> Option<Span>;
874
875 #[inline]
876 fn has_name(&self, name: Symbol) -> bool {
877 self.name().map(|x| x == name).unwrap_or(false)
878 }
879
880 #[inline]
881 fn has_any_name(&self, names: &[Symbol]) -> bool {
882 names.iter().any(|&name| self.has_name(name))
883 }
884
885 fn span(&self) -> Span;
887
888 fn is_word(&self) -> bool;
889
890 fn path(&self) -> SmallVec<[Symbol; 1]> {
891 self.symbol_path().unwrap_or(smallvec![sym::doc])
892 }
893
894 fn path_span(&self) -> Option<Span>;
895
896 fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
898
899 fn doc_str(&self) -> Option<Symbol>;
904
905 fn deprecation_note(&self) -> Option<Symbol>;
909
910 fn is_proc_macro_attr(&self) -> bool {
911 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
912 .iter()
913 .any(|kind| self.has_name(*kind))
914 }
915 fn is_automatically_derived_attr(&self) -> bool;
916
917 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
923
924 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
932
933 fn is_doc_hidden(&self) -> bool;
935
936 fn is_doc_keyword_or_attribute(&self) -> bool;
938}
939
940impl Attribute {
943 pub fn id(&self) -> AttrId {
944 AttributeExt::id(self)
945 }
946
947 pub fn name(&self) -> Option<Symbol> {
948 AttributeExt::name(self)
949 }
950
951 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
952 AttributeExt::meta_item_list(self)
953 }
954
955 pub fn value_str(&self) -> Option<Symbol> {
956 AttributeExt::value_str(self)
957 }
958
959 pub fn value_span(&self) -> Option<Span> {
960 AttributeExt::value_span(self)
961 }
962
963 pub fn path_matches(&self, name: &[Symbol]) -> bool {
964 AttributeExt::path_matches(self, name)
965 }
966
967 pub fn is_doc_comment(&self) -> bool {
969 AttributeExt::is_doc_comment(self).is_some()
970 }
971
972 #[inline]
973 pub fn has_name(&self, name: Symbol) -> bool {
974 AttributeExt::has_name(self, name)
975 }
976
977 #[inline]
978 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
979 AttributeExt::has_any_name(self, names)
980 }
981
982 pub fn span(&self) -> Span {
983 AttributeExt::span(self)
984 }
985
986 pub fn is_word(&self) -> bool {
987 AttributeExt::is_word(self)
988 }
989
990 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
991 AttributeExt::path(self)
992 }
993
994 pub fn doc_str(&self) -> Option<Symbol> {
995 AttributeExt::doc_str(self)
996 }
997
998 pub fn is_proc_macro_attr(&self) -> bool {
999 AttributeExt::is_proc_macro_attr(self)
1000 }
1001
1002 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
1003 AttributeExt::doc_str_and_fragment_kind(self)
1004 }
1005}