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.into_inner().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 style(&self) -> AttrStyle {
210 self.style
211 }
212}
213
214impl Attribute {
215 pub fn may_have_doc_links(&self) -> bool {
216 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
217 }
218
219 pub fn meta(&self) -> Option<MetaItem> {
221 match &self.kind {
222 AttrKind::Normal(normal) => normal.item.meta(self.span),
223 AttrKind::DocComment(..) => None,
224 }
225 }
226
227 pub fn meta_kind(&self) -> Option<MetaItemKind> {
228 match &self.kind {
229 AttrKind::Normal(normal) => normal.item.meta_kind(),
230 AttrKind::DocComment(..) => None,
231 }
232 }
233
234 pub fn token_trees(&self) -> Vec<TokenTree> {
235 match self.kind {
236 AttrKind::Normal(ref normal) => normal
237 .tokens
238 .as_ref()
239 .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
240 .to_attr_token_stream()
241 .to_token_trees(),
242 AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone(
243 token::DocComment(comment_kind, self.style, data),
244 self.span,
245 )],
246 }
247 }
248}
249
250impl AttrItem {
251 pub fn span(&self) -> Span {
252 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
253 }
254
255 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
256 match &self.args {
257 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
258 MetaItemKind::list_from_tokens(args.tokens.clone())
259 }
260 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
261 }
262 }
263
264 fn value_str(&self) -> Option<Symbol> {
277 match &self.args {
278 AttrArgs::Eq { expr, .. } => match expr.kind {
279 ExprKind::Lit(token_lit) => {
280 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
281 }
282 _ => None,
283 },
284 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
285 }
286 }
287
288 pub fn meta(&self, span: Span) -> Option<MetaItem> {
289 Some(MetaItem {
290 unsafety: Safety::Default,
291 path: self.path.clone(),
292 kind: self.meta_kind()?,
293 span,
294 })
295 }
296
297 pub fn meta_kind(&self) -> Option<MetaItemKind> {
298 MetaItemKind::from_attr_args(&self.args)
299 }
300}
301
302impl MetaItem {
303 pub fn ident(&self) -> Option<Ident> {
305 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
306 }
307
308 pub fn name(&self) -> Option<Symbol> {
309 self.ident().map(|ident| ident.name)
310 }
311
312 pub fn has_name(&self, name: Symbol) -> bool {
313 self.path == name
314 }
315
316 pub fn is_word(&self) -> bool {
317 matches!(self.kind, MetaItemKind::Word)
318 }
319
320 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
321 match &self.kind {
322 MetaItemKind::List(l) => Some(&**l),
323 _ => None,
324 }
325 }
326
327 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
333 match &self.kind {
334 MetaItemKind::NameValue(v) => Some(v),
335 _ => None,
336 }
337 }
338
339 pub fn name_value_literal_span(&self) -> Option<Span> {
347 Some(self.name_value_literal()?.span)
348 }
349
350 pub fn value_str(&self) -> Option<Symbol> {
363 match &self.kind {
364 MetaItemKind::NameValue(v) => v.kind.str(),
365 _ => None,
366 }
367 }
368
369 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
370 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
372 let path = match tt.as_deref() {
373 Some(&TokenTree::Token(
374 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
375 _,
376 )) => 'arm: {
377 let mut segments = if let &token::Ident(name, _) = kind {
378 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
379 iter.peek()
380 {
381 iter.next();
382 thin_vec![PathSegment::from_ident(Ident::new(name, span))]
383 } else {
384 break 'arm Path::from_ident(Ident::new(name, span));
385 }
386 } else {
387 thin_vec![PathSegment::path_root(span)]
388 };
389 loop {
390 if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
391 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
392 {
393 segments.push(PathSegment::from_ident(Ident::new(name, span)));
394 } else {
395 return None;
396 }
397 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
398 iter.peek()
399 {
400 iter.next();
401 } else {
402 break;
403 }
404 }
405 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
406 Path { span, segments, tokens: None }
407 }
408 Some(TokenTree::Delimited(
409 _span,
410 _spacing,
411 Delimiter::Invisible(InvisibleOrigin::MetaVar(
412 MetaVarKind::Meta { .. } | MetaVarKind::Path,
413 )),
414 _stream,
415 )) => {
416 unreachable!()
418 }
419 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
420 panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
421 }
422 _ => return None,
423 };
424 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
425 let kind = MetaItemKind::from_tokens(iter)?;
426 let hi = match &kind {
427 MetaItemKind::NameValue(lit) => lit.span.hi(),
428 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
429 _ => path.span.hi(),
430 };
431 let span = path.span.with_hi(hi);
432 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
436 }
437}
438
439impl MetaItemKind {
440 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
442 let mut iter = tokens.iter();
443 let mut result = ThinVec::new();
444 while iter.peek().is_some() {
445 let item = MetaItemInner::from_tokens(&mut iter)?;
446 result.push(item);
447 match iter.next() {
448 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
449 _ => return None,
450 }
451 }
452 Some(result)
453 }
454
455 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
456 match iter.next() {
457 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
458 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
459 }
460 Some(TokenTree::Token(token, _)) => {
461 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
462 }
463 _ => None,
464 }
465 }
466
467 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
468 match iter.peek() {
469 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
470 let inner_tokens = inner_tokens.clone();
471 iter.next();
472 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
473 }
474 Some(TokenTree::Delimited(..)) => None,
475 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
476 iter.next();
477 MetaItemKind::name_value_from_tokens(iter)
478 }
479 _ => Some(MetaItemKind::Word),
480 }
481 }
482
483 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
484 match args {
485 AttrArgs::Empty => Some(MetaItemKind::Word),
486 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
487 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
488 }
489 AttrArgs::Delimited(..) => None,
490 AttrArgs::Eq { expr, .. } => match expr.kind {
491 ExprKind::Lit(token_lit) => {
492 MetaItemLit::from_token_lit(token_lit, expr.span)
494 .ok()
495 .map(|lit| MetaItemKind::NameValue(lit))
496 }
497 _ => None,
498 },
499 }
500 }
501}
502
503impl MetaItemInner {
504 pub fn span(&self) -> Span {
505 match self {
506 MetaItemInner::MetaItem(item) => item.span,
507 MetaItemInner::Lit(lit) => lit.span,
508 }
509 }
510
511 pub fn ident(&self) -> Option<Ident> {
513 self.meta_item().and_then(|meta_item| meta_item.ident())
514 }
515
516 pub fn name(&self) -> Option<Symbol> {
518 self.ident().map(|ident| ident.name)
519 }
520
521 pub fn has_name(&self, name: Symbol) -> bool {
523 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
524 }
525
526 pub fn is_word(&self) -> bool {
528 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
529 }
530
531 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
533 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
534 }
535
536 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
539 self.meta_item().and_then(|meta_item| {
540 meta_item.meta_item_list().and_then(|meta_item_list| {
541 if meta_item_list.len() == 1
542 && let Some(ident) = meta_item.ident()
543 && let Some(lit) = meta_item_list[0].lit()
544 {
545 return Some((ident.name, lit));
546 }
547 None
548 })
549 })
550 }
551
552 pub fn name_value_literal_span(&self) -> Option<Span> {
554 self.meta_item()?.name_value_literal_span()
555 }
556
557 pub fn value_str(&self) -> Option<Symbol> {
560 self.meta_item().and_then(|meta_item| meta_item.value_str())
561 }
562
563 pub fn lit(&self) -> Option<&MetaItemLit> {
565 match self {
566 MetaItemInner::Lit(lit) => Some(lit),
567 _ => None,
568 }
569 }
570
571 pub fn boolean_literal(&self) -> Option<bool> {
573 match self {
574 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
575 _ => None,
576 }
577 }
578
579 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
582 match self {
583 MetaItemInner::MetaItem(_item) => Some(self),
584 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
585 _ => None,
586 }
587 }
588
589 pub fn meta_item(&self) -> Option<&MetaItem> {
591 match self {
592 MetaItemInner::MetaItem(item) => Some(item),
593 _ => None,
594 }
595 }
596
597 pub fn is_meta_item(&self) -> bool {
599 self.meta_item().is_some()
600 }
601
602 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
603 match iter.peek() {
604 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
605 iter.next();
606 return Some(MetaItemInner::Lit(lit));
607 }
608 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
609 iter.next();
610 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
611 }
612 _ => {}
613 }
614 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
615 }
616}
617
618pub fn mk_doc_comment(
619 g: &AttrIdGenerator,
620 comment_kind: CommentKind,
621 style: AttrStyle,
622 data: Symbol,
623 span: Span,
624) -> Attribute {
625 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
626}
627
628fn mk_attr(
629 g: &AttrIdGenerator,
630 style: AttrStyle,
631 unsafety: Safety,
632 path: Path,
633 args: AttrArgs,
634 span: Span,
635) -> Attribute {
636 mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
637}
638
639pub fn mk_attr_from_item(
640 g: &AttrIdGenerator,
641 item: AttrItem,
642 tokens: Option<LazyAttrTokenStream>,
643 style: AttrStyle,
644 span: Span,
645) -> Attribute {
646 Attribute {
647 kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
648 id: g.mk_attr_id(),
649 style,
650 span,
651 }
652}
653
654pub fn mk_attr_word(
655 g: &AttrIdGenerator,
656 style: AttrStyle,
657 unsafety: Safety,
658 name: Symbol,
659 span: Span,
660) -> Attribute {
661 let path = Path::from_ident(Ident::new(name, span));
662 let args = AttrArgs::Empty;
663 mk_attr(g, style, unsafety, path, args, span)
664}
665
666pub fn mk_attr_nested_word(
667 g: &AttrIdGenerator,
668 style: AttrStyle,
669 unsafety: Safety,
670 outer: Symbol,
671 inner: Symbol,
672 span: Span,
673) -> Attribute {
674 let inner_tokens = TokenStream::new(vec![TokenTree::Token(
675 Token::from_ast_ident(Ident::new(inner, span)),
676 Spacing::Alone,
677 )]);
678 let outer_ident = Ident::new(outer, span);
679 let path = Path::from_ident(outer_ident);
680 let attr_args = AttrArgs::Delimited(DelimArgs {
681 dspan: DelimSpan::from_single(span),
682 delim: Delimiter::Parenthesis,
683 tokens: inner_tokens,
684 });
685 mk_attr(g, style, unsafety, path, attr_args, span)
686}
687
688pub fn mk_attr_name_value_str(
689 g: &AttrIdGenerator,
690 style: AttrStyle,
691 unsafety: Safety,
692 name: Symbol,
693 val: Symbol,
694 span: Span,
695) -> Attribute {
696 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
697 let expr = P(Expr {
698 id: DUMMY_NODE_ID,
699 kind: ExprKind::Lit(lit),
700 span,
701 attrs: AttrVec::new(),
702 tokens: None,
703 });
704 let path = Path::from_ident(Ident::new(name, span));
705 let args = AttrArgs::Eq { eq_span: span, expr };
706 mk_attr(g, style, unsafety, path, args, span)
707}
708
709pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
710 attrs.iter().filter(move |attr| attr.has_name(name))
711}
712
713pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
714 filter_by_name(attrs, name).next()
715}
716
717pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
718 find_by_name(attrs, name).and_then(|attr| attr.value_str())
719}
720
721pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
722 find_by_name(attrs, name).is_some()
723}
724
725pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
726 items.iter().any(|item| item.has_name(name))
727}
728
729impl MetaItemLit {
730 pub fn value_str(&self) -> Option<Symbol> {
731 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
732 }
733}
734
735pub trait AttributeExt: Debug {
736 fn id(&self) -> AttrId;
737
738 fn name(&self) -> Option<Symbol> {
741 self.ident().map(|ident| ident.name)
742 }
743
744 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
746
747 fn value_str(&self) -> Option<Symbol>;
749
750 fn value_span(&self) -> Option<Span>;
752
753 fn ident(&self) -> Option<Ident>;
755
756 fn path_matches(&self, name: &[Symbol]) -> bool;
760
761 fn is_doc_comment(&self) -> bool;
765
766 #[inline]
767 fn has_name(&self, name: Symbol) -> bool {
768 self.ident().map(|x| x.name == name).unwrap_or(false)
769 }
770
771 #[inline]
772 fn has_any_name(&self, names: &[Symbol]) -> bool {
773 names.iter().any(|&name| self.has_name(name))
774 }
775
776 fn span(&self) -> Span;
778
779 fn is_word(&self) -> bool;
780
781 fn path(&self) -> SmallVec<[Symbol; 1]> {
782 self.ident_path()
783 .map(|i| i.into_iter().map(|i| i.name).collect())
784 .unwrap_or(smallvec![sym::doc])
785 }
786
787 fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
789
790 fn doc_str(&self) -> Option<Symbol>;
795
796 fn is_proc_macro_attr(&self) -> bool {
797 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
798 .iter()
799 .any(|kind| self.has_name(*kind))
800 }
801
802 fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>;
808
809 fn style(&self) -> AttrStyle;
810}
811
812impl Attribute {
815 pub fn id(&self) -> AttrId {
816 AttributeExt::id(self)
817 }
818
819 pub fn name(&self) -> Option<Symbol> {
820 AttributeExt::name(self)
821 }
822
823 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
824 AttributeExt::meta_item_list(self)
825 }
826
827 pub fn value_str(&self) -> Option<Symbol> {
828 AttributeExt::value_str(self)
829 }
830
831 pub fn value_span(&self) -> Option<Span> {
832 AttributeExt::value_span(self)
833 }
834
835 pub fn ident(&self) -> Option<Ident> {
836 AttributeExt::ident(self)
837 }
838
839 pub fn path_matches(&self, name: &[Symbol]) -> bool {
840 AttributeExt::path_matches(self, name)
841 }
842
843 pub fn is_doc_comment(&self) -> bool {
844 AttributeExt::is_doc_comment(self)
845 }
846
847 #[inline]
848 pub fn has_name(&self, name: Symbol) -> bool {
849 AttributeExt::has_name(self, name)
850 }
851
852 #[inline]
853 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
854 AttributeExt::has_any_name(self, names)
855 }
856
857 pub fn span(&self) -> Span {
858 AttributeExt::span(self)
859 }
860
861 pub fn is_word(&self) -> bool {
862 AttributeExt::is_word(self)
863 }
864
865 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
866 AttributeExt::path(self)
867 }
868
869 pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
870 AttributeExt::ident_path(self)
871 }
872
873 pub fn doc_str(&self) -> Option<Symbol> {
874 AttributeExt::doc_str(self)
875 }
876
877 pub fn is_proc_macro_attr(&self) -> bool {
878 AttributeExt::is_proc_macro_attr(self)
879 }
880
881 pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
882 AttributeExt::doc_str_and_comment_kind(self)
883 }
884
885 pub fn style(&self) -> AttrStyle {
886 AttributeExt::style(self)
887 }
888}