1use std::fmt::Debug;
4use std::sync::atomic::{AtomicU32, Ordering};
5
6use rustc_index::bit_set::GrowableBitSet;
7use rustc_span::{Ident, Span, Symbol, sym};
8use smallvec::{SmallVec, smallvec};
9use thin_vec::{ThinVec, thin_vec};
10
11use crate::ast::{
12 AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
13 Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
14 PathSegment, Safety,
15};
16use crate::ptr::P;
17use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token};
18use crate::tokenstream::{
19 DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
20};
21use crate::util::comments;
22use crate::util::literal::escape_string_symbol;
23
24pub struct MarkedAttrs(GrowableBitSet<AttrId>);
25
26impl MarkedAttrs {
27 pub fn new() -> Self {
28 MarkedAttrs(GrowableBitSet::new_empty())
31 }
32
33 pub fn mark(&mut self, attr: &Attribute) {
34 self.0.insert(attr.id);
35 }
36
37 pub fn is_marked(&self, attr: &Attribute) -> bool {
38 self.0.contains(attr.id)
39 }
40}
41
42pub struct AttrIdGenerator(AtomicU32);
43
44impl AttrIdGenerator {
45 pub fn new() -> Self {
46 AttrIdGenerator(AtomicU32::new(0))
47 }
48
49 pub fn mk_attr_id(&self) -> AttrId {
50 let id = self.0.fetch_add(1, Ordering::Relaxed);
51 assert!(id != u32::MAX);
52 AttrId::from_u32(id)
53 }
54}
55
56impl Attribute {
57 pub fn get_normal_item(&self) -> &AttrItem {
58 match &self.kind {
59 AttrKind::Normal(normal) => &normal.item,
60 AttrKind::DocComment(..) => panic!("unexpected doc comment"),
61 }
62 }
63
64 pub fn unwrap_normal_item(self) -> AttrItem {
65 match self.kind {
66 AttrKind::Normal(normal) => normal.item,
67 AttrKind::DocComment(..) => panic!("unexpected doc comment"),
68 }
69 }
70}
71
72impl AttributeExt for Attribute {
73 fn id(&self) -> AttrId {
74 self.id
75 }
76
77 fn value_span(&self) -> Option<Span> {
78 match &self.kind {
79 AttrKind::Normal(normal) => match &normal.item.args {
80 AttrArgs::Eq { expr, .. } => Some(expr.span),
81 _ => None,
82 },
83 AttrKind::DocComment(..) => None,
84 }
85 }
86
87 fn is_doc_comment(&self) -> bool {
91 match self.kind {
92 AttrKind::Normal(..) => false,
93 AttrKind::DocComment(..) => true,
94 }
95 }
96
97 fn ident(&self) -> Option<Ident> {
99 match &self.kind {
100 AttrKind::Normal(normal) => {
101 if let [ident] = &*normal.item.path.segments {
102 Some(ident.ident)
103 } else {
104 None
105 }
106 }
107 AttrKind::DocComment(..) => None,
108 }
109 }
110
111 fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
112 match &self.kind {
113 AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
114 AttrKind::DocComment(_, _) => None,
115 }
116 }
117
118 fn path_matches(&self, name: &[Symbol]) -> bool {
119 match &self.kind {
120 AttrKind::Normal(normal) => {
121 normal.item.path.segments.len() == name.len()
122 && normal
123 .item
124 .path
125 .segments
126 .iter()
127 .zip(name)
128 .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
129 }
130 AttrKind::DocComment(..) => false,
131 }
132 }
133
134 fn span(&self) -> Span {
135 self.span
136 }
137
138 fn is_word(&self) -> bool {
139 if let AttrKind::Normal(normal) = &self.kind {
140 matches!(normal.item.args, AttrArgs::Empty)
141 } else {
142 false
143 }
144 }
145
146 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
154 match &self.kind {
155 AttrKind::Normal(normal) => normal.item.meta_item_list(),
156 AttrKind::DocComment(..) => None,
157 }
158 }
159
160 fn value_str(&self) -> Option<Symbol> {
176 match &self.kind {
177 AttrKind::Normal(normal) => normal.item.value_str(),
178 AttrKind::DocComment(..) => None,
179 }
180 }
181
182 fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
188 match &self.kind {
189 AttrKind::DocComment(kind, data) => Some((*data, *kind)),
190 AttrKind::Normal(normal) if normal.item.path == sym::doc => {
191 normal.item.value_str().map(|s| (s, CommentKind::Line))
192 }
193 _ => None,
194 }
195 }
196
197 fn doc_str(&self) -> Option<Symbol> {
202 match &self.kind {
203 AttrKind::DocComment(.., data) => Some(*data),
204 AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
205 _ => None,
206 }
207 }
208
209 fn doc_resolution_scope(&self) -> Option<AttrStyle> {
210 match &self.kind {
211 AttrKind::DocComment(..) => Some(self.style),
212 AttrKind::Normal(normal)
213 if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
214 {
215 Some(self.style)
216 }
217 _ => None,
218 }
219 }
220
221 fn is_automatically_derived_attr(&self) -> bool {
222 self.has_name(sym::automatically_derived)
223 }
224}
225
226impl Attribute {
227 pub fn style(&self) -> AttrStyle {
228 self.style
229 }
230
231 pub fn may_have_doc_links(&self) -> bool {
232 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
233 }
234
235 pub fn meta(&self) -> Option<MetaItem> {
237 match &self.kind {
238 AttrKind::Normal(normal) => normal.item.meta(self.span),
239 AttrKind::DocComment(..) => None,
240 }
241 }
242
243 pub fn meta_kind(&self) -> Option<MetaItemKind> {
244 match &self.kind {
245 AttrKind::Normal(normal) => normal.item.meta_kind(),
246 AttrKind::DocComment(..) => None,
247 }
248 }
249
250 pub fn token_trees(&self) -> Vec<TokenTree> {
251 match self.kind {
252 AttrKind::Normal(ref normal) => normal
253 .tokens
254 .as_ref()
255 .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
256 .to_attr_token_stream()
257 .to_token_trees(),
258 AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone(
259 token::DocComment(comment_kind, self.style, data),
260 self.span,
261 )],
262 }
263 }
264}
265
266impl AttrItem {
267 pub fn span(&self) -> Span {
268 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
269 }
270
271 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
272 match &self.args {
273 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
274 MetaItemKind::list_from_tokens(args.tokens.clone())
275 }
276 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
277 }
278 }
279
280 fn value_str(&self) -> Option<Symbol> {
293 match &self.args {
294 AttrArgs::Eq { expr, .. } => match expr.kind {
295 ExprKind::Lit(token_lit) => {
296 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
297 }
298 _ => None,
299 },
300 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
301 }
302 }
303
304 pub fn meta(&self, span: Span) -> Option<MetaItem> {
305 Some(MetaItem {
306 unsafety: Safety::Default,
307 path: self.path.clone(),
308 kind: self.meta_kind()?,
309 span,
310 })
311 }
312
313 pub fn meta_kind(&self) -> Option<MetaItemKind> {
314 MetaItemKind::from_attr_args(&self.args)
315 }
316}
317
318impl MetaItem {
319 pub fn ident(&self) -> Option<Ident> {
321 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
322 }
323
324 pub fn name(&self) -> Option<Symbol> {
325 self.ident().map(|ident| ident.name)
326 }
327
328 pub fn has_name(&self, name: Symbol) -> bool {
329 self.path == name
330 }
331
332 pub fn is_word(&self) -> bool {
333 matches!(self.kind, MetaItemKind::Word)
334 }
335
336 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
337 match &self.kind {
338 MetaItemKind::List(l) => Some(&**l),
339 _ => None,
340 }
341 }
342
343 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
349 match &self.kind {
350 MetaItemKind::NameValue(v) => Some(v),
351 _ => None,
352 }
353 }
354
355 pub fn name_value_literal_span(&self) -> Option<Span> {
363 Some(self.name_value_literal()?.span)
364 }
365
366 pub fn value_str(&self) -> Option<Symbol> {
379 match &self.kind {
380 MetaItemKind::NameValue(v) => v.kind.str(),
381 _ => None,
382 }
383 }
384
385 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
386 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
388 let path = match tt.as_deref() {
389 Some(&TokenTree::Token(
390 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
391 _,
392 )) => 'arm: {
393 let mut segments = if let &token::Ident(name, _) = kind {
394 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
395 iter.peek()
396 {
397 iter.next();
398 thin_vec![PathSegment::from_ident(Ident::new(name, span))]
399 } else {
400 break 'arm Path::from_ident(Ident::new(name, span));
401 }
402 } else {
403 thin_vec![PathSegment::path_root(span)]
404 };
405 loop {
406 if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
407 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
408 {
409 segments.push(PathSegment::from_ident(Ident::new(name, span)));
410 } else {
411 return None;
412 }
413 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
414 iter.peek()
415 {
416 iter.next();
417 } else {
418 break;
419 }
420 }
421 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
422 Path { span, segments, tokens: None }
423 }
424 Some(TokenTree::Delimited(
425 _span,
426 _spacing,
427 Delimiter::Invisible(InvisibleOrigin::MetaVar(
428 MetaVarKind::Meta { .. } | MetaVarKind::Path,
429 )),
430 _stream,
431 )) => {
432 unreachable!()
434 }
435 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
436 panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
437 }
438 _ => return None,
439 };
440 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
441 let kind = MetaItemKind::from_tokens(iter)?;
442 let hi = match &kind {
443 MetaItemKind::NameValue(lit) => lit.span.hi(),
444 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
445 _ => path.span.hi(),
446 };
447 let span = path.span.with_hi(hi);
448 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
452 }
453}
454
455impl MetaItemKind {
456 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
458 let mut iter = tokens.iter();
459 let mut result = ThinVec::new();
460 while iter.peek().is_some() {
461 let item = MetaItemInner::from_tokens(&mut iter)?;
462 result.push(item);
463 match iter.next() {
464 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
465 _ => return None,
466 }
467 }
468 Some(result)
469 }
470
471 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
472 match iter.next() {
473 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
474 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
475 }
476 Some(TokenTree::Token(token, _)) => {
477 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
478 }
479 _ => None,
480 }
481 }
482
483 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
484 match iter.peek() {
485 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
486 let inner_tokens = inner_tokens.clone();
487 iter.next();
488 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
489 }
490 Some(TokenTree::Delimited(..)) => None,
491 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
492 iter.next();
493 MetaItemKind::name_value_from_tokens(iter)
494 }
495 _ => Some(MetaItemKind::Word),
496 }
497 }
498
499 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
500 match args {
501 AttrArgs::Empty => Some(MetaItemKind::Word),
502 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
503 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
504 }
505 AttrArgs::Delimited(..) => None,
506 AttrArgs::Eq { expr, .. } => match expr.kind {
507 ExprKind::Lit(token_lit) => {
508 MetaItemLit::from_token_lit(token_lit, expr.span)
510 .ok()
511 .map(|lit| MetaItemKind::NameValue(lit))
512 }
513 _ => None,
514 },
515 }
516 }
517}
518
519impl MetaItemInner {
520 pub fn span(&self) -> Span {
521 match self {
522 MetaItemInner::MetaItem(item) => item.span,
523 MetaItemInner::Lit(lit) => lit.span,
524 }
525 }
526
527 pub fn ident(&self) -> Option<Ident> {
529 self.meta_item().and_then(|meta_item| meta_item.ident())
530 }
531
532 pub fn name(&self) -> Option<Symbol> {
534 self.ident().map(|ident| ident.name)
535 }
536
537 pub fn has_name(&self, name: Symbol) -> bool {
539 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
540 }
541
542 pub fn is_word(&self) -> bool {
544 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
545 }
546
547 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
549 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
550 }
551
552 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
555 self.meta_item().and_then(|meta_item| {
556 meta_item.meta_item_list().and_then(|meta_item_list| {
557 if meta_item_list.len() == 1
558 && let Some(ident) = meta_item.ident()
559 && let Some(lit) = meta_item_list[0].lit()
560 {
561 return Some((ident.name, lit));
562 }
563 None
564 })
565 })
566 }
567
568 pub fn name_value_literal_span(&self) -> Option<Span> {
570 self.meta_item()?.name_value_literal_span()
571 }
572
573 pub fn value_str(&self) -> Option<Symbol> {
576 self.meta_item().and_then(|meta_item| meta_item.value_str())
577 }
578
579 pub fn lit(&self) -> Option<&MetaItemLit> {
581 match self {
582 MetaItemInner::Lit(lit) => Some(lit),
583 _ => None,
584 }
585 }
586
587 pub fn boolean_literal(&self) -> Option<bool> {
589 match self {
590 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
591 _ => None,
592 }
593 }
594
595 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
598 match self {
599 MetaItemInner::MetaItem(_item) => Some(self),
600 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
601 _ => None,
602 }
603 }
604
605 pub fn meta_item(&self) -> Option<&MetaItem> {
607 match self {
608 MetaItemInner::MetaItem(item) => Some(item),
609 _ => None,
610 }
611 }
612
613 pub fn is_meta_item(&self) -> bool {
615 self.meta_item().is_some()
616 }
617
618 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
619 match iter.peek() {
620 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
621 iter.next();
622 return Some(MetaItemInner::Lit(lit));
623 }
624 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
625 iter.next();
626 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
627 }
628 _ => {}
629 }
630 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
631 }
632}
633
634pub fn mk_doc_comment(
635 g: &AttrIdGenerator,
636 comment_kind: CommentKind,
637 style: AttrStyle,
638 data: Symbol,
639 span: Span,
640) -> Attribute {
641 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
642}
643
644fn mk_attr(
645 g: &AttrIdGenerator,
646 style: AttrStyle,
647 unsafety: Safety,
648 path: Path,
649 args: AttrArgs,
650 span: Span,
651) -> Attribute {
652 mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
653}
654
655pub fn mk_attr_from_item(
656 g: &AttrIdGenerator,
657 item: AttrItem,
658 tokens: Option<LazyAttrTokenStream>,
659 style: AttrStyle,
660 span: Span,
661) -> Attribute {
662 Attribute {
663 kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
664 id: g.mk_attr_id(),
665 style,
666 span,
667 }
668}
669
670pub fn mk_attr_word(
671 g: &AttrIdGenerator,
672 style: AttrStyle,
673 unsafety: Safety,
674 name: Symbol,
675 span: Span,
676) -> Attribute {
677 let path = Path::from_ident(Ident::new(name, span));
678 let args = AttrArgs::Empty;
679 mk_attr(g, style, unsafety, path, args, span)
680}
681
682pub fn mk_attr_nested_word(
683 g: &AttrIdGenerator,
684 style: AttrStyle,
685 unsafety: Safety,
686 outer: Symbol,
687 inner: Symbol,
688 span: Span,
689) -> Attribute {
690 let inner_tokens = TokenStream::new(vec![TokenTree::Token(
691 Token::from_ast_ident(Ident::new(inner, span)),
692 Spacing::Alone,
693 )]);
694 let outer_ident = Ident::new(outer, span);
695 let path = Path::from_ident(outer_ident);
696 let attr_args = AttrArgs::Delimited(DelimArgs {
697 dspan: DelimSpan::from_single(span),
698 delim: Delimiter::Parenthesis,
699 tokens: inner_tokens,
700 });
701 mk_attr(g, style, unsafety, path, attr_args, span)
702}
703
704pub fn mk_attr_name_value_str(
705 g: &AttrIdGenerator,
706 style: AttrStyle,
707 unsafety: Safety,
708 name: Symbol,
709 val: Symbol,
710 span: Span,
711) -> Attribute {
712 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
713 let expr = P(Expr {
714 id: DUMMY_NODE_ID,
715 kind: ExprKind::Lit(lit),
716 span,
717 attrs: AttrVec::new(),
718 tokens: None,
719 });
720 let path = Path::from_ident(Ident::new(name, span));
721 let args = AttrArgs::Eq { eq_span: span, expr };
722 mk_attr(g, style, unsafety, path, args, span)
723}
724
725pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
726 attrs.iter().filter(move |attr| attr.has_name(name))
727}
728
729pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
730 filter_by_name(attrs, name).next()
731}
732
733pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
734 find_by_name(attrs, name).and_then(|attr| attr.value_str())
735}
736
737pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
738 find_by_name(attrs, name).is_some()
739}
740
741pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
742 items.iter().any(|item| item.has_name(name))
743}
744
745impl MetaItemLit {
746 pub fn value_str(&self) -> Option<Symbol> {
747 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
748 }
749}
750
751pub trait AttributeExt: Debug {
752 fn id(&self) -> AttrId;
753
754 fn name(&self) -> Option<Symbol> {
757 self.ident().map(|ident| ident.name)
758 }
759
760 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
762
763 fn value_str(&self) -> Option<Symbol>;
765
766 fn value_span(&self) -> Option<Span>;
768
769 fn ident(&self) -> Option<Ident>;
771
772 fn path_matches(&self, name: &[Symbol]) -> bool;
776
777 fn is_doc_comment(&self) -> bool;
781
782 #[inline]
783 fn has_name(&self, name: Symbol) -> bool {
784 self.ident().map(|x| x.name == name).unwrap_or(false)
785 }
786
787 #[inline]
788 fn has_any_name(&self, names: &[Symbol]) -> bool {
789 names.iter().any(|&name| self.has_name(name))
790 }
791
792 fn span(&self) -> Span;
794
795 fn is_word(&self) -> bool;
796
797 fn path(&self) -> SmallVec<[Symbol; 1]> {
798 self.ident_path()
799 .map(|i| i.into_iter().map(|i| i.name).collect())
800 .unwrap_or(smallvec![sym::doc])
801 }
802
803 fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
805
806 fn doc_str(&self) -> Option<Symbol>;
811
812 fn is_proc_macro_attr(&self) -> bool {
813 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
814 .iter()
815 .any(|kind| self.has_name(*kind))
816 }
817 fn is_automatically_derived_attr(&self) -> bool;
818
819 fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>;
825
826 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
834}
835
836impl Attribute {
839 pub fn id(&self) -> AttrId {
840 AttributeExt::id(self)
841 }
842
843 pub fn name(&self) -> Option<Symbol> {
844 AttributeExt::name(self)
845 }
846
847 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
848 AttributeExt::meta_item_list(self)
849 }
850
851 pub fn value_str(&self) -> Option<Symbol> {
852 AttributeExt::value_str(self)
853 }
854
855 pub fn value_span(&self) -> Option<Span> {
856 AttributeExt::value_span(self)
857 }
858
859 pub fn ident(&self) -> Option<Ident> {
860 AttributeExt::ident(self)
861 }
862
863 pub fn path_matches(&self, name: &[Symbol]) -> bool {
864 AttributeExt::path_matches(self, name)
865 }
866
867 pub fn is_doc_comment(&self) -> bool {
868 AttributeExt::is_doc_comment(self)
869 }
870
871 #[inline]
872 pub fn has_name(&self, name: Symbol) -> bool {
873 AttributeExt::has_name(self, name)
874 }
875
876 #[inline]
877 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
878 AttributeExt::has_any_name(self, names)
879 }
880
881 pub fn span(&self) -> Span {
882 AttributeExt::span(self)
883 }
884
885 pub fn is_word(&self) -> bool {
886 AttributeExt::is_word(self)
887 }
888
889 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
890 AttributeExt::path(self)
891 }
892
893 pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
894 AttributeExt::ident_path(self)
895 }
896
897 pub fn doc_str(&self) -> Option<Symbol> {
898 AttributeExt::doc_str(self)
899 }
900
901 pub fn is_proc_macro_attr(&self) -> bool {
902 AttributeExt::is_proc_macro_attr(self)
903 }
904
905 pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
906 AttributeExt::doc_str_and_comment_kind(self)
907 }
908}