1
1
use super :: ptr:: P ;
2
- use super :: tokenstream:: LazyTokenStream ;
2
+ use super :: tokenstream:: { LazyTokenStream , Spacing , AttributesData , PreexpTokenTree , PreexpTokenStream } ;
3
3
use super :: { Arm , Field , FieldPat , GenericParam , Param , StructField , Variant } ;
4
- use super :: { AssocItem , Expr , ForeignItem , Item , Local } ;
4
+ use super :: { AssocItem , Expr , ForeignItem , Item , Local , MacCallStmt } ;
5
5
use super :: { AttrItem , AttrKind , Block , Pat , Path , Ty , Visibility } ;
6
6
use super :: { AttrVec , Attribute , Stmt , StmtKind } ;
7
+ use rustc_span:: sym;
7
8
8
9
/// An `AstLike` represents an AST node (or some wrapper around
9
10
/// and AST node) which stores some combination of attributes
10
11
/// and tokens.
11
12
pub trait AstLike : Sized {
13
+ const SUPPORTS_INNER_ATTRS : bool ;
12
14
fn attrs ( & self ) -> & [ Attribute ] ;
13
15
fn visit_attrs ( & mut self , f : impl FnOnce ( & mut Vec < Attribute > ) ) ;
14
16
/// Called by `Parser::collect_tokens` to store the collected
15
17
/// tokens inside an AST node
16
- fn finalize_tokens ( & mut self , _tokens : LazyTokenStream ) {
18
+ fn finalize_tokens ( & mut self , _tokens : LazyTokenStream ) -> Option < AttributesData > {
17
19
// This default impl makes this trait easier to implement
18
20
// in tools like `rust-analyzer`
19
21
panic ! ( "`finalize_tokens` is not supported!" )
20
22
}
23
+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) ;
21
24
}
22
25
23
26
impl < T : AstLike + ' static > AstLike for P < T > {
27
+ const SUPPORTS_INNER_ATTRS : bool = T :: SUPPORTS_INNER_ATTRS ;
24
28
fn attrs ( & self ) -> & [ Attribute ] {
25
29
( * * self ) . attrs ( )
26
30
}
27
31
fn visit_attrs ( & mut self , f : impl FnOnce ( & mut Vec < Attribute > ) ) {
28
32
( * * self ) . visit_attrs ( f) ;
29
33
}
30
- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
34
+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
31
35
( * * self ) . finalize_tokens ( tokens)
32
36
}
37
+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
38
+ ( * * self ) . visit_tokens ( f) ;
39
+ }
33
40
}
34
41
35
42
fn visit_attrvec ( attrs : & mut AttrVec , f : impl FnOnce ( & mut Vec < Attribute > ) ) {
@@ -41,6 +48,10 @@ fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
41
48
}
42
49
43
50
impl AstLike for StmtKind {
51
+ // This might be an `StmtKind::Item`, which contains
52
+ // an item that supports inner attrs
53
+ const SUPPORTS_INNER_ATTRS : bool = true ;
54
+
44
55
fn attrs ( & self ) -> & [ Attribute ] {
45
56
match * self {
46
57
StmtKind :: Local ( ref local) => local. attrs ( ) ,
@@ -60,53 +71,85 @@ impl AstLike for StmtKind {
60
71
StmtKind :: MacCall ( mac) => visit_attrvec ( & mut mac. attrs , f) ,
61
72
}
62
73
}
63
- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
64
- let stmt_tokens = match self {
65
- StmtKind :: Local ( ref mut local) => & mut local. tokens ,
66
- StmtKind :: Item ( ref mut item) => & mut item. tokens ,
67
- StmtKind :: Expr ( ref mut expr) | StmtKind :: Semi ( ref mut expr) => & mut expr. tokens ,
68
- StmtKind :: Empty => return ,
69
- StmtKind :: MacCall ( ref mut mac) => & mut mac. tokens ,
74
+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
75
+ match self {
76
+ StmtKind :: Local ( ref mut local) => local. finalize_tokens ( tokens) ,
77
+ StmtKind :: MacCall ( ref mut mac) => mac. finalize_tokens ( tokens) ,
78
+ StmtKind :: Expr ( ref mut expr) | StmtKind :: Semi ( ref mut expr) => {
79
+ expr. finalize_tokens ( tokens)
80
+ }
81
+ StmtKind :: Item ( ref mut item) => item. finalize_tokens ( tokens) ,
82
+ StmtKind :: Empty => None ,
83
+ }
84
+ }
85
+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
86
+ let tokens = match self {
87
+ StmtKind :: Local ( ref mut local) => Some ( & mut local. tokens ) ,
88
+ StmtKind :: Item ( ref mut item) => Some ( & mut item. tokens ) ,
89
+ StmtKind :: Expr ( ref mut expr) | StmtKind :: Semi ( ref mut expr) => Some ( & mut expr. tokens ) ,
90
+ StmtKind :: Empty => None ,
91
+ StmtKind :: MacCall ( ref mut mac) => Some ( & mut mac. tokens ) ,
70
92
} ;
71
- if stmt_tokens . is_none ( ) {
72
- * stmt_tokens = Some ( tokens) ;
93
+ if let Some ( tokens ) = tokens {
94
+ f ( tokens) ;
73
95
}
74
96
}
75
97
}
76
98
77
99
impl AstLike for Stmt {
100
+ const SUPPORTS_INNER_ATTRS : bool = StmtKind :: SUPPORTS_INNER_ATTRS ;
101
+
78
102
fn attrs ( & self ) -> & [ Attribute ] {
79
103
self . kind . attrs ( )
80
104
}
81
105
82
106
fn visit_attrs ( & mut self , f : impl FnOnce ( & mut Vec < Attribute > ) ) {
83
107
self . kind . visit_attrs ( f) ;
84
108
}
85
- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
109
+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
86
110
self . kind . finalize_tokens ( tokens)
87
111
}
112
+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
113
+ self . kind . visit_tokens ( f)
114
+ }
88
115
}
89
116
90
117
impl AstLike for Attribute {
118
+ const SUPPORTS_INNER_ATTRS : bool = false ;
119
+
91
120
fn attrs ( & self ) -> & [ Attribute ] {
92
121
& [ ]
93
122
}
94
123
fn visit_attrs ( & mut self , _f : impl FnOnce ( & mut Vec < Attribute > ) ) { }
95
- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
124
+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
96
125
match & mut self . kind {
97
126
AttrKind :: Normal ( _, attr_tokens) => {
98
127
if attr_tokens. is_none ( ) {
99
128
* attr_tokens = Some ( tokens) ;
100
129
}
130
+ None
101
131
}
102
132
AttrKind :: DocComment ( ..) => {
103
133
panic ! ( "Called finalize_tokens on doc comment attr {:?}" , self )
104
134
}
105
135
}
106
136
}
137
+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
138
+ match & mut self . kind {
139
+ AttrKind :: Normal ( _, attr_tokens) => {
140
+ f ( attr_tokens) ;
141
+ }
142
+ AttrKind :: DocComment ( ..) => {
143
+ panic ! ( "Called visit_tokens on doc comment attr {:?}" , self )
144
+ }
145
+ }
146
+
147
+ }
107
148
}
108
149
109
150
impl < T : AstLike > AstLike for Option < T > {
151
+ const SUPPORTS_INNER_ATTRS : bool = T :: SUPPORTS_INNER_ATTRS ;
152
+
110
153
fn attrs ( & self ) -> & [ Attribute ] {
111
154
self . as_ref ( ) . map ( |inner| inner. attrs ( ) ) . unwrap_or ( & [ ] )
112
155
}
@@ -115,13 +158,26 @@ impl<T: AstLike> AstLike for Option<T> {
115
158
inner. visit_attrs ( f) ;
116
159
}
117
160
}
118
- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
161
+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
162
+ self . as_mut ( ) . and_then ( |inner| inner. finalize_tokens ( tokens) )
163
+ }
164
+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
119
165
if let Some ( inner) = self {
120
- inner. finalize_tokens ( tokens ) ;
166
+ inner. visit_tokens ( f ) ;
121
167
}
122
168
}
123
169
}
124
170
171
+ // NOTE: Builtin attributes like `cfg` and `cfg_attr` cannot be renamed via imports.
172
+ // Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that
173
+ // we don't need to do any eager expansion.
174
+ pub fn has_cfg_or_cfg_any ( attrs : & [ Attribute ] ) -> bool {
175
+ attrs. iter ( ) . any ( |attr| {
176
+ attr. ident ( ) . map_or ( false , |ident| ident. name == sym:: cfg || ident. name == sym:: cfg_attr)
177
+ } )
178
+ }
179
+
180
+
125
181
/// Helper trait for the macros below. Abstracts over
126
182
/// the two types of attribute fields that AST nodes
127
183
/// may have (`Vec<Attribute>` or `AttrVec`)
@@ -142,8 +198,13 @@ impl VecOrAttrVec for AttrVec {
142
198
}
143
199
144
200
macro_rules! derive_has_tokens_and_attrs {
145
- ( $( $ty: path) ,* ) => { $(
201
+ (
202
+ const SUPPORTS_INNER_ATTRS : bool = $inner_attrs: literal;
203
+ $( $ty: path) ,*
204
+ ) => { $(
146
205
impl AstLike for $ty {
206
+ const SUPPORTS_INNER_ATTRS : bool = $inner_attrs;
207
+
147
208
fn attrs( & self ) -> & [ Attribute ] {
148
209
& self . attrs
149
210
}
@@ -152,19 +213,31 @@ macro_rules! derive_has_tokens_and_attrs {
152
213
VecOrAttrVec :: visit( & mut self . attrs, f)
153
214
}
154
215
155
- fn finalize_tokens( & mut self , tokens: LazyTokenStream ) {
216
+ fn finalize_tokens( & mut self , tokens: LazyTokenStream ) -> Option < AttributesData > {
156
217
if self . tokens. is_none( ) {
157
218
self . tokens = Some ( tokens) ;
158
219
}
159
220
221
+ if has_cfg_or_cfg_any( & self . attrs) {
222
+ Some ( AttributesData { attrs: self . attrs. clone( ) . into( ) , tokens: self . tokens. clone( ) . unwrap( ) } )
223
+ } else {
224
+ None
225
+ }
226
+ }
227
+
228
+ fn visit_tokens( & mut self , f: impl FnOnce ( & mut Option <LazyTokenStream >) ) {
229
+ f( & mut self . tokens)
160
230
}
231
+
161
232
}
162
233
) * }
163
234
}
164
235
165
236
macro_rules! derive_has_attrs_no_tokens {
166
237
( $( $ty: path) ,* ) => { $(
167
238
impl AstLike for $ty {
239
+ const SUPPORTS_INNER_ATTRS : bool = false ;
240
+
168
241
fn attrs( & self ) -> & [ Attribute ] {
169
242
& self . attrs
170
243
}
@@ -173,35 +246,61 @@ macro_rules! derive_has_attrs_no_tokens {
173
246
VecOrAttrVec :: visit( & mut self . attrs, f)
174
247
}
175
248
176
- fn finalize_tokens( & mut self , _tokens: LazyTokenStream ) { }
249
+ fn finalize_tokens( & mut self , tokens: LazyTokenStream ) -> Option <AttributesData > {
250
+ if has_cfg_or_cfg_any( & self . attrs) {
251
+ Some ( AttributesData { attrs: self . attrs. clone( ) . into( ) , tokens } )
252
+ } else {
253
+ None
254
+ }
255
+ }
256
+ fn visit_tokens( & mut self , _f: impl FnOnce ( & mut Option <LazyTokenStream >) ) { }
257
+
177
258
}
178
259
) * }
179
260
}
180
261
181
262
macro_rules! derive_has_tokens_no_attrs {
182
263
( $( $ty: path) ,* ) => { $(
183
264
impl AstLike for $ty {
265
+ const SUPPORTS_INNER_ATTRS : bool = false ;
266
+
184
267
fn attrs( & self ) -> & [ Attribute ] {
185
268
& [ ]
186
269
}
187
270
188
271
fn visit_attrs( & mut self , _f: impl FnOnce ( & mut Vec <Attribute >) ) {
189
272
}
190
273
191
- fn finalize_tokens( & mut self , tokens: LazyTokenStream ) {
274
+ fn finalize_tokens( & mut self , tokens: LazyTokenStream ) -> Option <AttributesData > {
275
+ // FIXME - stoer them directly?
192
276
if self . tokens. is_none( ) {
193
- self . tokens = Some ( tokens) ;
277
+ self . tokens = Some ( LazyTokenStream :: new( PreexpTokenStream :: new( vec![
278
+ ( PreexpTokenTree :: Attributes ( AttributesData {
279
+ attrs: Default :: default ( ) ,
280
+ tokens,
281
+ } ) , Spacing :: Alone ) ] ) ) ) ;
194
282
}
195
-
283
+ None
284
+ }
285
+ fn visit_tokens( & mut self , f: impl FnOnce ( & mut Option <LazyTokenStream >) ) {
286
+ f( & mut self . tokens)
196
287
}
197
288
}
198
289
) * }
199
290
}
200
291
201
- // These AST nodes support both inert and active
202
- // attributes, so they also have tokens.
292
+ // These ast nodes support both active and inert attributes,
293
+ // so they have tokens collected to pass to proc macros
294
+ derive_has_tokens_and_attrs ! {
295
+ // Both `Item` and `AssocItem` can have bodies, which
296
+ // can contain inner attributes
297
+ const SUPPORTS_INNER_ATTRS : bool = true ;
298
+ Item , AssocItem
299
+ }
300
+
203
301
derive_has_tokens_and_attrs ! {
204
- Item , Expr , Local , AssocItem , ForeignItem
302
+ const SUPPORTS_INNER_ATTRS : bool = false ;
303
+ ForeignItem , Expr , Local , MacCallStmt
205
304
}
206
305
207
306
// These ast nodes only support inert attributes, so they don't
0 commit comments