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