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::{
17 self, CommentKind, Delimiter, DocFragmentKind, InvisibleOrigin, MetaVarKind, Token,
18};
19use crate::tokenstream::{
20 DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
21};
22use crate::util::comments;
23use crate::util::literal::escape_string_symbol;
24
25pub struct MarkedAttrs(GrowableBitSet<AttrId>);
26
27impl MarkedAttrs {
28 pub fn new() -> Self {
29 MarkedAttrs(GrowableBitSet::new_empty())
32 }
33
34 pub fn mark(&mut self, attr: &Attribute) {
35 self.0.insert(attr.id);
36 }
37
38 pub fn is_marked(&self, attr: &Attribute) -> bool {
39 self.0.contains(attr.id)
40 }
41}
42
43pub struct AttrIdGenerator(AtomicU32);
44
45impl AttrIdGenerator {
46 pub fn new() -> Self {
47 AttrIdGenerator(AtomicU32::new(0))
48 }
49
50 pub fn mk_attr_id(&self) -> AttrId {
51 let id = self.0.fetch_add(1, Ordering::Relaxed);
52 assert!(id != u32::MAX);
53 AttrId::from_u32(id)
54 }
55}
56
57impl Attribute {
58 pub fn get_normal_item(&self) -> &AttrItem {
59 match &self.kind {
60 AttrKind::Normal(normal) => &normal.item,
61 AttrKind::DocComment(..) => panic!("unexpected doc comment"),
62 }
63 }
64
65 pub fn unwrap_normal_item(self) -> AttrItem {
66 match self.kind {
67 AttrKind::Normal(normal) => normal.item,
68 AttrKind::DocComment(..) => panic!("unexpected doc comment"),
69 }
70 }
71}
72
73impl AttributeExt for Attribute {
74 fn id(&self) -> AttrId {
75 self.id
76 }
77
78 fn value_span(&self) -> Option<Span> {
79 match &self.kind {
80 AttrKind::Normal(normal) => match &normal.item.args {
81 AttrArgs::Eq { expr, .. } => Some(expr.span),
82 _ => None,
83 },
84 AttrKind::DocComment(..) => None,
85 }
86 }
87
88 fn is_doc_comment(&self) -> Option<Span> {
92 match self.kind {
93 AttrKind::Normal(..) => None,
94 AttrKind::DocComment(..) => Some(self.span),
95 }
96 }
97
98 fn ident(&self) -> Option<Ident> {
100 match &self.kind {
101 AttrKind::Normal(normal) => {
102 if let [ident] = &*normal.item.path.segments {
103 Some(ident.ident)
104 } else {
105 None
106 }
107 }
108 AttrKind::DocComment(..) => None,
109 }
110 }
111
112 fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
113 match &self.kind {
114 AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
115 AttrKind::DocComment(_, _) => None,
116 }
117 }
118
119 fn path_matches(&self, name: &[Symbol]) -> bool {
120 match &self.kind {
121 AttrKind::Normal(normal) => {
122 normal.item.path.segments.len() == name.len()
123 && normal
124 .item
125 .path
126 .segments
127 .iter()
128 .zip(name)
129 .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
130 }
131 AttrKind::DocComment(..) => false,
132 }
133 }
134
135 fn span(&self) -> Span {
136 self.span
137 }
138
139 fn is_word(&self) -> bool {
140 if let AttrKind::Normal(normal) = &self.kind {
141 matches!(normal.item.args, AttrArgs::Empty)
142 } else {
143 false
144 }
145 }
146
147 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
155 match &self.kind {
156 AttrKind::Normal(normal) => normal.item.meta_item_list(),
157 AttrKind::DocComment(..) => None,
158 }
159 }
160
161 fn value_str(&self) -> Option<Symbol> {
177 match &self.kind {
178 AttrKind::Normal(normal) => normal.item.value_str(),
179 AttrKind::DocComment(..) => None,
180 }
181 }
182
183 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
189 match &self.kind {
190 AttrKind::DocComment(kind, data) => Some((*data, DocFragmentKind::Sugared(*kind))),
191 AttrKind::Normal(normal) if normal.item.path == sym::doc => {
192 if let Some(value) = normal.item.value_str()
193 && let Some(value_span) = normal.item.value_span()
194 {
195 Some((value, DocFragmentKind::Raw(value_span)))
196 } else {
197 None
198 }
199 }
200 _ => None,
201 }
202 }
203
204 fn doc_str(&self) -> Option<Symbol> {
209 match &self.kind {
210 AttrKind::DocComment(.., data) => Some(*data),
211 AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
212 _ => None,
213 }
214 }
215
216 fn doc_resolution_scope(&self) -> Option<AttrStyle> {
217 match &self.kind {
218 AttrKind::DocComment(..) => Some(self.style),
219 AttrKind::Normal(normal)
220 if normal.item.path == sym::doc && normal.item.value_str().is_some() =>
221 {
222 Some(self.style)
223 }
224 _ => None,
225 }
226 }
227
228 fn is_automatically_derived_attr(&self) -> bool {
229 self.has_name(sym::automatically_derived)
230 }
231
232 fn is_doc_hidden(&self) -> bool {
233 self.has_name(sym::doc)
234 && self.meta_item_list().is_some_and(|l| list_contains_name(&l, sym::hidden))
235 }
236
237 fn is_doc_keyword_or_attribute(&self) -> bool {
238 if self.has_name(sym::doc)
239 && let Some(items) = self.meta_item_list()
240 {
241 for item in items {
242 if item.has_name(sym::keyword) || item.has_name(sym::attribute) {
243 return true;
244 }
245 }
246 }
247 false
248 }
249}
250
251impl Attribute {
252 pub fn style(&self) -> AttrStyle {
253 self.style
254 }
255
256 pub fn may_have_doc_links(&self) -> bool {
257 self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
258 }
259
260 pub fn meta(&self) -> Option<MetaItem> {
262 match &self.kind {
263 AttrKind::Normal(normal) => normal.item.meta(self.span),
264 AttrKind::DocComment(..) => None,
265 }
266 }
267
268 pub fn meta_kind(&self) -> Option<MetaItemKind> {
269 match &self.kind {
270 AttrKind::Normal(normal) => normal.item.meta_kind(),
271 AttrKind::DocComment(..) => None,
272 }
273 }
274
275 pub fn token_trees(&self) -> Vec<TokenTree> {
276 match self.kind {
277 AttrKind::Normal(ref normal) => normal
278 .tokens
279 .as_ref()
280 .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
281 .to_attr_token_stream()
282 .to_token_trees(),
283 AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone(
284 token::DocComment(comment_kind, self.style, data),
285 self.span,
286 )],
287 }
288 }
289}
290
291impl AttrItem {
292 pub fn span(&self) -> Span {
293 self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
294 }
295
296 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
297 match &self.args {
298 AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
299 MetaItemKind::list_from_tokens(args.tokens.clone())
300 }
301 AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
302 }
303 }
304
305 fn value_str(&self) -> Option<Symbol> {
318 match &self.args {
319 AttrArgs::Eq { expr, .. } => match expr.kind {
320 ExprKind::Lit(token_lit) => {
321 LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
322 }
323 _ => None,
324 },
325 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
326 }
327 }
328
329 fn value_span(&self) -> Option<Span> {
342 match &self.args {
343 AttrArgs::Eq { expr, .. } => Some(expr.span),
344 AttrArgs::Delimited(_) | AttrArgs::Empty => None,
345 }
346 }
347
348 pub fn meta(&self, span: Span) -> Option<MetaItem> {
349 Some(MetaItem {
350 unsafety: Safety::Default,
351 path: self.path.clone(),
352 kind: self.meta_kind()?,
353 span,
354 })
355 }
356
357 pub fn meta_kind(&self) -> Option<MetaItemKind> {
358 MetaItemKind::from_attr_args(&self.args)
359 }
360}
361
362impl MetaItem {
363 pub fn ident(&self) -> Option<Ident> {
365 if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
366 }
367
368 pub fn name(&self) -> Option<Symbol> {
369 self.ident().map(|ident| ident.name)
370 }
371
372 pub fn has_name(&self, name: Symbol) -> bool {
373 self.path == name
374 }
375
376 pub fn is_word(&self) -> bool {
377 matches!(self.kind, MetaItemKind::Word)
378 }
379
380 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
381 match &self.kind {
382 MetaItemKind::List(l) => Some(&**l),
383 _ => None,
384 }
385 }
386
387 pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
393 match &self.kind {
394 MetaItemKind::NameValue(v) => Some(v),
395 _ => None,
396 }
397 }
398
399 pub fn name_value_literal_span(&self) -> Option<Span> {
407 Some(self.name_value_literal()?.span)
408 }
409
410 pub fn value_str(&self) -> Option<Symbol> {
423 match &self.kind {
424 MetaItemKind::NameValue(v) => v.kind.str(),
425 _ => None,
426 }
427 }
428
429 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
430 let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
432 let path = match tt.as_deref() {
433 Some(&TokenTree::Token(
434 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
435 _,
436 )) => 'arm: {
437 let mut segments = if let &token::Ident(name, _) = kind {
438 if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
439 iter.peek()
440 {
441 iter.next();
442 thin_vec![PathSegment::from_ident(Ident::new(name, span))]
443 } else {
444 break 'arm Path::from_ident(Ident::new(name, span));
445 }
446 } else {
447 thin_vec![PathSegment::path_root(span)]
448 };
449 loop {
450 let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
451 iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
452 else {
453 return None;
454 };
455 segments.push(PathSegment::from_ident(Ident::new(name, span)));
456 let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
457 else {
458 break;
459 };
460 iter.next();
461 }
462 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
463 Path { span, segments, tokens: None }
464 }
465 Some(TokenTree::Delimited(
466 _span,
467 _spacing,
468 Delimiter::Invisible(InvisibleOrigin::MetaVar(
469 MetaVarKind::Meta { .. } | MetaVarKind::Path,
470 )),
471 _stream,
472 )) => {
473 unreachable!()
475 }
476 Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
477 panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
478 }
479 _ => return None,
480 };
481 let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
482 let kind = MetaItemKind::from_tokens(iter)?;
483 let hi = match &kind {
484 MetaItemKind::NameValue(lit) => lit.span.hi(),
485 MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
486 _ => path.span.hi(),
487 };
488 let span = path.span.with_hi(hi);
489 Some(MetaItem { unsafety: Safety::Default, path, kind, span })
493 }
494}
495
496impl MetaItemKind {
497 pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
499 let mut iter = tokens.iter();
500 let mut result = ThinVec::new();
501 while iter.peek().is_some() {
502 let item = MetaItemInner::from_tokens(&mut iter)?;
503 result.push(item);
504 match iter.next() {
505 None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
506 _ => return None,
507 }
508 }
509 Some(result)
510 }
511
512 fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
513 match iter.next() {
514 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
515 MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
516 }
517 Some(TokenTree::Token(token, _)) => {
518 MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
519 }
520 _ => None,
521 }
522 }
523
524 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
525 match iter.peek() {
526 Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
527 let inner_tokens = inner_tokens.clone();
528 iter.next();
529 MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
530 }
531 Some(TokenTree::Delimited(..)) => None,
532 Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
533 iter.next();
534 MetaItemKind::name_value_from_tokens(iter)
535 }
536 _ => Some(MetaItemKind::Word),
537 }
538 }
539
540 fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
541 match args {
542 AttrArgs::Empty => Some(MetaItemKind::Word),
543 AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
544 MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
545 }
546 AttrArgs::Delimited(..) => None,
547 AttrArgs::Eq { expr, .. } => match expr.kind {
548 ExprKind::Lit(token_lit) => {
549 MetaItemLit::from_token_lit(token_lit, expr.span)
551 .ok()
552 .map(|lit| MetaItemKind::NameValue(lit))
553 }
554 _ => None,
555 },
556 }
557 }
558}
559
560impl MetaItemInner {
561 pub fn span(&self) -> Span {
562 match self {
563 MetaItemInner::MetaItem(item) => item.span,
564 MetaItemInner::Lit(lit) => lit.span,
565 }
566 }
567
568 pub fn ident(&self) -> Option<Ident> {
570 self.meta_item().and_then(|meta_item| meta_item.ident())
571 }
572
573 pub fn name(&self) -> Option<Symbol> {
575 self.ident().map(|ident| ident.name)
576 }
577
578 pub fn has_name(&self, name: Symbol) -> bool {
580 self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
581 }
582
583 pub fn is_word(&self) -> bool {
585 self.meta_item().is_some_and(|meta_item| meta_item.is_word())
586 }
587
588 pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> {
590 self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
591 }
592
593 pub fn singleton_lit_list(&self) -> Option<(Symbol, &MetaItemLit)> {
596 self.meta_item().and_then(|meta_item| {
597 meta_item.meta_item_list().and_then(|meta_item_list| {
598 if meta_item_list.len() == 1
599 && let Some(ident) = meta_item.ident()
600 && let Some(lit) = meta_item_list[0].lit()
601 {
602 return Some((ident.name, lit));
603 }
604 None
605 })
606 })
607 }
608
609 pub fn name_value_literal_span(&self) -> Option<Span> {
611 self.meta_item()?.name_value_literal_span()
612 }
613
614 pub fn value_str(&self) -> Option<Symbol> {
617 self.meta_item().and_then(|meta_item| meta_item.value_str())
618 }
619
620 pub fn lit(&self) -> Option<&MetaItemLit> {
622 match self {
623 MetaItemInner::Lit(lit) => Some(lit),
624 _ => None,
625 }
626 }
627
628 pub fn boolean_literal(&self) -> Option<bool> {
630 match self {
631 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => Some(*b),
632 _ => None,
633 }
634 }
635
636 pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> {
639 match self {
640 MetaItemInner::MetaItem(_item) => Some(self),
641 MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
642 _ => None,
643 }
644 }
645
646 pub fn meta_item(&self) -> Option<&MetaItem> {
648 match self {
649 MetaItemInner::MetaItem(item) => Some(item),
650 _ => None,
651 }
652 }
653
654 pub fn is_meta_item(&self) -> bool {
656 self.meta_item().is_some()
657 }
658
659 fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
660 match iter.peek() {
661 Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
662 iter.next();
663 return Some(MetaItemInner::Lit(lit));
664 }
665 Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
666 iter.next();
667 return MetaItemInner::from_tokens(&mut inner_tokens.iter());
668 }
669 _ => {}
670 }
671 MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
672 }
673}
674
675pub fn mk_doc_comment(
676 g: &AttrIdGenerator,
677 comment_kind: CommentKind,
678 style: AttrStyle,
679 data: Symbol,
680 span: Span,
681) -> Attribute {
682 Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
683}
684
685fn mk_attr(
686 g: &AttrIdGenerator,
687 style: AttrStyle,
688 unsafety: Safety,
689 path: Path,
690 args: AttrArgs,
691 span: Span,
692) -> Attribute {
693 mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
694}
695
696pub fn mk_attr_from_item(
697 g: &AttrIdGenerator,
698 item: AttrItem,
699 tokens: Option<LazyAttrTokenStream>,
700 style: AttrStyle,
701 span: Span,
702) -> Attribute {
703 Attribute {
704 kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
705 id: g.mk_attr_id(),
706 style,
707 span,
708 }
709}
710
711pub fn mk_attr_word(
712 g: &AttrIdGenerator,
713 style: AttrStyle,
714 unsafety: Safety,
715 name: Symbol,
716 span: Span,
717) -> Attribute {
718 let path = Path::from_ident(Ident::new(name, span));
719 let args = AttrArgs::Empty;
720 mk_attr(g, style, unsafety, path, args, span)
721}
722
723pub fn mk_attr_nested_word(
724 g: &AttrIdGenerator,
725 style: AttrStyle,
726 unsafety: Safety,
727 outer: Symbol,
728 inner: Symbol,
729 span: Span,
730) -> Attribute {
731 let inner_tokens = TokenStream::new(vec![TokenTree::Token(
732 Token::from_ast_ident(Ident::new(inner, span)),
733 Spacing::Alone,
734 )]);
735 let outer_ident = Ident::new(outer, span);
736 let path = Path::from_ident(outer_ident);
737 let attr_args = AttrArgs::Delimited(DelimArgs {
738 dspan: DelimSpan::from_single(span),
739 delim: Delimiter::Parenthesis,
740 tokens: inner_tokens,
741 });
742 mk_attr(g, style, unsafety, path, attr_args, span)
743}
744
745pub fn mk_attr_name_value_str(
746 g: &AttrIdGenerator,
747 style: AttrStyle,
748 unsafety: Safety,
749 name: Symbol,
750 val: Symbol,
751 span: Span,
752) -> Attribute {
753 let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
754 let expr = Box::new(Expr {
755 id: DUMMY_NODE_ID,
756 kind: ExprKind::Lit(lit),
757 span,
758 attrs: AttrVec::new(),
759 tokens: None,
760 });
761 let path = Path::from_ident(Ident::new(name, span));
762 let args = AttrArgs::Eq { eq_span: span, expr };
763 mk_attr(g, style, unsafety, path, args, span)
764}
765
766pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
767 attrs.iter().filter(move |attr| attr.has_name(name))
768}
769
770pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
771 filter_by_name(attrs, name).next()
772}
773
774pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
775 find_by_name(attrs, name).and_then(|attr| attr.value_str())
776}
777
778pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
779 find_by_name(attrs, name).is_some()
780}
781
782pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
783 items.iter().any(|item| item.has_name(name))
784}
785
786impl MetaItemLit {
787 pub fn value_str(&self) -> Option<Symbol> {
788 LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
789 }
790}
791
792pub trait AttributeExt: Debug {
793 fn id(&self) -> AttrId;
794
795 fn name(&self) -> Option<Symbol> {
798 self.ident().map(|ident| ident.name)
799 }
800
801 fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
803
804 fn value_str(&self) -> Option<Symbol>;
806
807 fn value_span(&self) -> Option<Span>;
809
810 fn ident(&self) -> Option<Ident>;
812
813 fn path_matches(&self, name: &[Symbol]) -> bool;
817
818 fn is_doc_comment(&self) -> Option<Span>;
822
823 #[inline]
824 fn has_name(&self, name: Symbol) -> bool {
825 self.ident().map(|x| x.name == name).unwrap_or(false)
826 }
827
828 #[inline]
829 fn has_any_name(&self, names: &[Symbol]) -> bool {
830 names.iter().any(|&name| self.has_name(name))
831 }
832
833 fn span(&self) -> Span;
835
836 fn is_word(&self) -> bool;
837
838 fn path(&self) -> SmallVec<[Symbol; 1]> {
839 self.ident_path()
840 .map(|i| i.into_iter().map(|i| i.name).collect())
841 .unwrap_or(smallvec![sym::doc])
842 }
843
844 fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
846
847 fn doc_str(&self) -> Option<Symbol>;
852
853 fn is_proc_macro_attr(&self) -> bool {
854 [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
855 .iter()
856 .any(|kind| self.has_name(*kind))
857 }
858 fn is_automatically_derived_attr(&self) -> bool;
859
860 fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)>;
866
867 fn doc_resolution_scope(&self) -> Option<AttrStyle>;
875
876 fn is_doc_hidden(&self) -> bool;
878
879 fn is_doc_keyword_or_attribute(&self) -> bool;
881}
882
883impl Attribute {
886 pub fn id(&self) -> AttrId {
887 AttributeExt::id(self)
888 }
889
890 pub fn name(&self) -> Option<Symbol> {
891 AttributeExt::name(self)
892 }
893
894 pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
895 AttributeExt::meta_item_list(self)
896 }
897
898 pub fn value_str(&self) -> Option<Symbol> {
899 AttributeExt::value_str(self)
900 }
901
902 pub fn value_span(&self) -> Option<Span> {
903 AttributeExt::value_span(self)
904 }
905
906 pub fn ident(&self) -> Option<Ident> {
907 AttributeExt::ident(self)
908 }
909
910 pub fn path_matches(&self, name: &[Symbol]) -> bool {
911 AttributeExt::path_matches(self, name)
912 }
913
914 pub fn is_doc_comment(&self) -> bool {
916 AttributeExt::is_doc_comment(self).is_some()
917 }
918
919 #[inline]
920 pub fn has_name(&self, name: Symbol) -> bool {
921 AttributeExt::has_name(self, name)
922 }
923
924 #[inline]
925 pub fn has_any_name(&self, names: &[Symbol]) -> bool {
926 AttributeExt::has_any_name(self, names)
927 }
928
929 pub fn span(&self) -> Span {
930 AttributeExt::span(self)
931 }
932
933 pub fn is_word(&self) -> bool {
934 AttributeExt::is_word(self)
935 }
936
937 pub fn path(&self) -> SmallVec<[Symbol; 1]> {
938 AttributeExt::path(self)
939 }
940
941 pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
942 AttributeExt::ident_path(self)
943 }
944
945 pub fn doc_str(&self) -> Option<Symbol> {
946 AttributeExt::doc_str(self)
947 }
948
949 pub fn is_proc_macro_attr(&self) -> bool {
950 AttributeExt::is_proc_macro_attr(self)
951 }
952
953 pub fn doc_str_and_fragment_kind(&self) -> Option<(Symbol, DocFragmentKind)> {
954 AttributeExt::doc_str_and_fragment_kind(self)
955 }
956}