@@ -53,33 +53,30 @@ impl AttrIdGenerator {
5353 }
5454}
5555
56- impl 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- }
56+ impl AttributeExt for Attribute {
57+ fn id ( & self ) -> AttrId {
58+ self . id
6259 }
6360
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" ) ,
61+ fn value_str ( & self ) -> Option < Symbol > {
62+ match & self . kind {
63+ AttrKind :: Normal ( normal) => normal. item . value_str ( ) ,
64+ AttrKind :: DocComment ( ..) => None ,
6865 }
6966 }
7067
71- /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
72- /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
73- /// a doc comment) will return `false`.
74- pub fn is_doc_comment ( & self ) -> bool {
75- match self . kind {
76- AttrKind :: Normal ( .. ) => false ,
77- AttrKind :: DocComment ( ..) => true ,
68+ fn value_span ( & self ) -> Option < Span > {
69+ match & self . kind {
70+ AttrKind :: Normal ( normal ) => match & normal . item . args {
71+ AttrArgs :: Eq ( _ , l ) => Some ( l . span ) ,
72+ _ => None ,
73+ } ,
74+ AttrKind :: DocComment ( ..) => None ,
7875 }
7976 }
8077
8178 /// For a single-segment attribute, returns its name; otherwise, returns `None`.
82- pub fn ident ( & self ) -> Option < Ident > {
79+ fn ident ( & self ) -> Option < Ident > {
8380 match & self . kind {
8481 AttrKind :: Normal ( normal) => {
8582 if let [ ident] = & * normal. item . path . segments {
@@ -92,28 +89,7 @@ impl Attribute {
9289 }
9390 }
9491
95- pub fn name_or_empty ( & self ) -> Symbol {
96- self . ident ( ) . unwrap_or_else ( Ident :: empty) . name
97- }
98-
99- pub fn path ( & self ) -> SmallVec < [ Symbol ; 1 ] > {
100- match & self . kind {
101- AttrKind :: Normal ( normal) => {
102- normal. item . path . segments . iter ( ) . map ( |s| s. ident . name ) . collect ( )
103- }
104- AttrKind :: DocComment ( ..) => smallvec ! [ sym:: doc] ,
105- }
106- }
107-
108- #[ inline]
109- pub fn has_name ( & self , name : Symbol ) -> bool {
110- match & self . kind {
111- AttrKind :: Normal ( normal) => normal. item . path == name,
112- AttrKind :: DocComment ( ..) => false ,
113- }
114- }
115-
116- pub fn path_matches ( & self , name : & [ Symbol ] ) -> bool {
92+ fn path_matches ( & self , name : & [ Symbol ] ) -> bool {
11793 match & self . kind {
11894 AttrKind :: Normal ( normal) => {
11995 normal. item . path . segments . len ( ) == name. len ( )
@@ -129,34 +105,45 @@ impl Attribute {
129105 }
130106 }
131107
132- pub fn is_word ( & self ) -> bool {
108+ fn is_doc_comment ( & self ) -> bool {
109+ match self . kind {
110+ AttrKind :: Normal ( ..) => false ,
111+ AttrKind :: DocComment ( ..) => true ,
112+ }
113+ }
114+
115+ fn span ( & self ) -> Span {
116+ self . span
117+ }
118+
119+ fn is_word ( & self ) -> bool {
133120 if let AttrKind :: Normal ( normal) = & self . kind {
134121 matches ! ( normal. item. args, AttrArgs :: Empty )
135122 } else {
136123 false
137124 }
138125 }
139126
140- pub fn meta_item_list ( & self ) -> Option < ThinVec < MetaItemInner > > {
127+ fn meta_item_list ( & self ) -> Option < ThinVec < MetaItemInner > > {
141128 match & self . kind {
142129 AttrKind :: Normal ( normal) => normal. item . meta_item_list ( ) ,
143130 AttrKind :: DocComment ( ..) => None ,
144131 }
145132 }
146133
147- pub fn value_str ( & self ) -> Option < Symbol > {
134+ /// Returns the documentation if this is a doc comment or a sugared doc comment.
135+ /// * `///doc` returns `Some("doc")`.
136+ /// * `#[doc = "doc"]` returns `Some("doc")`.
137+ /// * `#[doc(...)]` returns `None`.
138+ fn doc_str ( & self ) -> Option < Symbol > {
148139 match & self . kind {
149- AttrKind :: Normal ( normal) => normal. item . value_str ( ) ,
150- AttrKind :: DocComment ( ..) => None ,
140+ AttrKind :: DocComment ( .., data) => Some ( * data) ,
141+ AttrKind :: Normal ( normal) if normal. item . path == sym:: doc => normal. item . value_str ( ) ,
142+ _ => None ,
151143 }
152144 }
153145
154- /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
155- /// * `///doc` returns `Some(("doc", CommentKind::Line))`.
156- /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
157- /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
158- /// * `#[doc(...)]` returns `None`.
159- pub fn doc_str_and_comment_kind ( & self ) -> Option < ( Symbol , CommentKind ) > {
146+ fn doc_str_and_comment_kind ( & self ) -> Option < ( Symbol , CommentKind ) > {
160147 match & self . kind {
161148 AttrKind :: DocComment ( kind, data) => Some ( ( * data, * kind) ) ,
162149 AttrKind :: Normal ( normal) if normal. item . path == sym:: doc => {
@@ -166,26 +153,35 @@ impl Attribute {
166153 }
167154 }
168155
169- /// Returns the documentation if this is a doc comment or a sugared doc comment.
170- /// * `///doc` returns `Some("doc")`.
171- /// * `#[doc = "doc"]` returns `Some("doc")`.
172- /// * `#[doc(...)]` returns `None`.
173- pub fn doc_str ( & self ) -> Option < Symbol > {
156+ fn style ( & self ) -> AttrStyle {
157+ self . style
158+ }
159+
160+ fn ident_path ( & self ) -> Option < SmallVec < [ Ident ; 1 ] > > {
174161 match & self . kind {
175- AttrKind :: DocComment ( .., data) => Some ( * data) ,
176- AttrKind :: Normal ( normal) if normal. item . path == sym:: doc => normal. item . value_str ( ) ,
177- _ => None ,
162+ AttrKind :: Normal ( p) => Some ( p. item . path . segments . iter ( ) . map ( |i| i. ident ) . collect ( ) ) ,
163+ AttrKind :: DocComment ( _, _) => None ,
178164 }
179165 }
166+ }
180167
181- pub fn may_have_doc_links ( & self ) -> bool {
182- self . doc_str ( ) . is_some_and ( |s| comments:: may_have_doc_links ( s. as_str ( ) ) )
168+ impl Attribute {
169+ pub fn get_normal_item ( & self ) -> & AttrItem {
170+ match & self . kind {
171+ AttrKind :: Normal ( normal) => & normal. item ,
172+ AttrKind :: DocComment ( ..) => panic ! ( "unexpected doc comment" ) ,
173+ }
183174 }
184175
185- pub fn is_proc_macro_attr ( & self ) -> bool {
186- [ sym:: proc_macro, sym:: proc_macro_attribute, sym:: proc_macro_derive]
187- . iter ( )
188- . any ( |kind| self . has_name ( * kind) )
176+ pub fn unwrap_normal_item ( self ) -> AttrItem {
177+ match self . kind {
178+ AttrKind :: Normal ( normal) => normal. into_inner ( ) . item ,
179+ AttrKind :: DocComment ( ..) => panic ! ( "unexpected doc comment" ) ,
180+ }
181+ }
182+
183+ pub fn may_have_doc_links ( & self ) -> bool {
184+ self . doc_str ( ) . is_some_and ( |s| comments:: may_have_doc_links ( s. as_str ( ) ) )
189185 }
190186
191187 /// Extracts the MetaItem from inside this Attribute.
@@ -235,7 +231,12 @@ impl AttrItem {
235231
236232 fn value_str ( & self ) -> Option < Symbol > {
237233 match & self . args {
238- AttrArgs :: Eq ( _, args) => args. value_str ( ) ,
234+ AttrArgs :: Eq ( _, expr) => match expr. kind {
235+ ExprKind :: Lit ( token_lit) => {
236+ LitKind :: from_token_lit ( token_lit) . ok ( ) . and_then ( |lit| lit. str ( ) )
237+ }
238+ _ => None ,
239+ } ,
239240 AttrArgs :: Delimited ( _) | AttrArgs :: Empty => None ,
240241 }
241242 }
@@ -380,7 +381,8 @@ impl MetaItem {
380381}
381382
382383impl MetaItemKind {
383- fn list_from_tokens ( tokens : TokenStream ) -> Option < ThinVec < MetaItemInner > > {
384+ // public because it can be called in the hir
385+ pub fn list_from_tokens ( tokens : TokenStream ) -> Option < ThinVec < MetaItemInner > > {
384386 let mut tokens = tokens. trees ( ) . peekable ( ) ;
385387 let mut result = ThinVec :: new ( ) ;
386388 while tokens. peek ( ) . is_some ( ) {
@@ -642,26 +644,102 @@ pub fn mk_attr_name_value_str(
642644 tokens : None ,
643645 } ) ;
644646 let path = Path :: from_ident ( Ident :: new ( name, span) ) ;
645- let args = AttrArgs :: Eq ( span, AttrArgsEq :: Ast ( expr) ) ;
647+ let args = AttrArgs :: Eq ( span, expr) ;
646648 mk_attr ( g, style, unsafety, path, args, span)
647649}
648650
649- pub fn filter_by_name ( attrs : & [ Attribute ] , name : Symbol ) -> impl Iterator < Item = & Attribute > {
651+ pub fn filter_by_name < A : AttributeExt > ( attrs : & [ A ] , name : Symbol ) -> impl Iterator < Item = & A > {
650652 attrs. iter ( ) . filter ( move |attr| attr. has_name ( name) )
651653}
652654
653- pub fn find_by_name ( attrs : & [ Attribute ] , name : Symbol ) -> Option < & Attribute > {
655+ pub fn find_by_name < A : AttributeExt > ( attrs : & [ A ] , name : Symbol ) -> Option < & A > {
654656 filter_by_name ( attrs, name) . next ( )
655657}
656658
657- pub fn first_attr_value_str_by_name ( attrs : & [ Attribute ] , name : Symbol ) -> Option < Symbol > {
659+ pub fn first_attr_value_str_by_name ( attrs : & [ impl AttributeExt ] , name : Symbol ) -> Option < Symbol > {
658660 find_by_name ( attrs, name) . and_then ( |attr| attr. value_str ( ) )
659661}
660662
661- pub fn contains_name ( attrs : & [ Attribute ] , name : Symbol ) -> bool {
663+ pub fn contains_name ( attrs : & [ impl AttributeExt ] , name : Symbol ) -> bool {
662664 find_by_name ( attrs, name) . is_some ( )
663665}
664666
665667pub fn list_contains_name ( items : & [ MetaItemInner ] , name : Symbol ) -> bool {
666668 items. iter ( ) . any ( |item| item. has_name ( name) )
667669}
670+
671+ impl MetaItemLit {
672+ pub fn value_str ( & self ) -> Option < Symbol > {
673+ LitKind :: from_token_lit ( self . as_token_lit ( ) ) . ok ( ) . and_then ( |lit| lit. str ( ) )
674+ }
675+ }
676+
677+ pub trait AttributeExt : Debug {
678+ fn id ( & self ) -> AttrId ;
679+
680+ fn name_or_empty ( & self ) -> Symbol {
681+ self . ident ( ) . unwrap_or_else ( Ident :: empty) . name
682+ }
683+
684+ /// Get the meta item list, `#[attr(meta item list)]`
685+ fn meta_item_list ( & self ) -> Option < ThinVec < MetaItemInner > > ;
686+
687+ /// Gets the value literal, as string, when using `#[attr = value]`
688+ fn value_str ( & self ) -> Option < Symbol > ;
689+
690+ /// Gets the span of the value literal, as string, when using `#[attr = value]`
691+ fn value_span ( & self ) -> Option < Span > ;
692+
693+ /// For a single-segment attribute, returns its name; otherwise, returns `None`.
694+ fn ident ( & self ) -> Option < Ident > ;
695+
696+ /// Checks whether the path of this attribute matches the name.
697+ ///
698+ /// Matches one segment of the path to each element in `name`
699+ fn path_matches ( & self , name : & [ Symbol ] ) -> bool ;
700+
701+ /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
702+ /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
703+ /// a doc comment) will return `false`.
704+ fn is_doc_comment ( & self ) -> bool ;
705+
706+ #[ inline]
707+ fn has_name ( & self , name : Symbol ) -> bool {
708+ self . ident ( ) . map ( |x| x. name == name) . unwrap_or ( false )
709+ }
710+
711+ /// get the span of the entire attribute
712+ fn span ( & self ) -> Span ;
713+
714+ fn is_word ( & self ) -> bool ;
715+
716+ fn path ( & self ) -> SmallVec < [ Symbol ; 1 ] > {
717+ self . ident_path ( )
718+ . map ( |i| i. into_iter ( ) . map ( |i| i. name ) . collect ( ) )
719+ . unwrap_or ( smallvec ! [ sym:: doc] )
720+ }
721+
722+ /// Returns None for doc comments
723+ fn ident_path ( & self ) -> Option < SmallVec < [ Ident ; 1 ] > > ;
724+
725+ /// Returns the documentation if this is a doc comment or a sugared doc comment.
726+ /// * `///doc` returns `Some("doc")`.
727+ /// * `#[doc = "doc"]` returns `Some("doc")`.
728+ /// * `#[doc(...)]` returns `None`.
729+ fn doc_str ( & self ) -> Option < Symbol > ;
730+
731+ fn is_proc_macro_attr ( & self ) -> bool {
732+ [ sym:: proc_macro, sym:: proc_macro_attribute, sym:: proc_macro_derive]
733+ . iter ( )
734+ . any ( |kind| self . has_name ( * kind) )
735+ }
736+
737+ /// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
738+ /// * `///doc` returns `Some(("doc", CommentKind::Line))`.
739+ /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
740+ /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
741+ /// * `#[doc(...)]` returns `None`.
742+ fn doc_str_and_comment_kind ( & self ) -> Option < ( Symbol , CommentKind ) > ;
743+
744+ fn style ( & self ) -> AttrStyle ;
745+ }
0 commit comments