@@ -53,33 +53,30 @@ impl AttrIdGenerator {
53
53
}
54
54
}
55
55
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
62
59
}
63
60
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 ,
68
65
}
69
66
}
70
67
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 ,
78
75
}
79
76
}
80
77
81
78
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
82
- pub fn ident ( & self ) -> Option < Ident > {
79
+ fn ident ( & self ) -> Option < Ident > {
83
80
match & self . kind {
84
81
AttrKind :: Normal ( normal) => {
85
82
if let [ ident] = & * normal. item . path . segments {
@@ -92,28 +89,7 @@ impl Attribute {
92
89
}
93
90
}
94
91
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 {
117
93
match & self . kind {
118
94
AttrKind :: Normal ( normal) => {
119
95
normal. item . path . segments . len ( ) == name. len ( )
@@ -129,34 +105,45 @@ impl Attribute {
129
105
}
130
106
}
131
107
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 {
133
120
if let AttrKind :: Normal ( normal) = & self . kind {
134
121
matches ! ( normal. item. args, AttrArgs :: Empty )
135
122
} else {
136
123
false
137
124
}
138
125
}
139
126
140
- pub fn meta_item_list ( & self ) -> Option < ThinVec < MetaItemInner > > {
127
+ fn meta_item_list ( & self ) -> Option < ThinVec < MetaItemInner > > {
141
128
match & self . kind {
142
129
AttrKind :: Normal ( normal) => normal. item . meta_item_list ( ) ,
143
130
AttrKind :: DocComment ( ..) => None ,
144
131
}
145
132
}
146
133
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 > {
148
139
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 ,
151
143
}
152
144
}
153
145
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 ) > {
160
147
match & self . kind {
161
148
AttrKind :: DocComment ( kind, data) => Some ( ( * data, * kind) ) ,
162
149
AttrKind :: Normal ( normal) if normal. item . path == sym:: doc => {
@@ -166,26 +153,35 @@ impl Attribute {
166
153
}
167
154
}
168
155
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 ] > > {
174
161
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 ,
178
164
}
179
165
}
166
+ }
180
167
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
+ }
183
174
}
184
175
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 ( ) ) )
189
185
}
190
186
191
187
/// Extracts the MetaItem from inside this Attribute.
@@ -235,7 +231,12 @@ impl AttrItem {
235
231
236
232
fn value_str ( & self ) -> Option < Symbol > {
237
233
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
+ } ,
239
240
AttrArgs :: Delimited ( _) | AttrArgs :: Empty => None ,
240
241
}
241
242
}
@@ -380,7 +381,8 @@ impl MetaItem {
380
381
}
381
382
382
383
impl 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 > > {
384
386
let mut tokens = tokens. trees ( ) . peekable ( ) ;
385
387
let mut result = ThinVec :: new ( ) ;
386
388
while tokens. peek ( ) . is_some ( ) {
@@ -642,26 +644,102 @@ pub fn mk_attr_name_value_str(
642
644
tokens : None ,
643
645
} ) ;
644
646
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) ;
646
648
mk_attr ( g, style, unsafety, path, args, span)
647
649
}
648
650
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 > {
650
652
attrs. iter ( ) . filter ( move |attr| attr. has_name ( name) )
651
653
}
652
654
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 > {
654
656
filter_by_name ( attrs, name) . next ( )
655
657
}
656
658
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 > {
658
660
find_by_name ( attrs, name) . and_then ( |attr| attr. value_str ( ) )
659
661
}
660
662
661
- pub fn contains_name ( attrs : & [ Attribute ] , name : Symbol ) -> bool {
663
+ pub fn contains_name ( attrs : & [ impl AttributeExt ] , name : Symbol ) -> bool {
662
664
find_by_name ( attrs, name) . is_some ( )
663
665
}
664
666
665
667
pub fn list_contains_name ( items : & [ MetaItemInner ] , name : Symbol ) -> bool {
666
668
items. iter ( ) . any ( |item| item. has_name ( name) )
667
669
}
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