16
16
use crate :: ast:: { AttrStyle , StmtKind } ;
17
17
use crate :: ast_traits:: { HasAttrs , HasTokens } ;
18
18
use crate :: token:: { self , Delimiter , Nonterminal , Token , TokenKind } ;
19
- use crate :: AttrVec ;
19
+ use crate :: { AttrVec , Attribute } ;
20
20
21
21
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
22
22
use rustc_data_structures:: sync:: { self , Lrc } ;
@@ -179,11 +179,10 @@ impl AttrTokenStream {
179
179
AttrTokenStream ( Lrc :: new ( tokens) )
180
180
}
181
181
182
- /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`.
183
- /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened'
184
- /// back to a `TokenStream` of the form `outer_attr attr_target`.
185
- /// If there are inner attributes, they are inserted into the proper
186
- /// place in the attribute target tokens.
182
+ /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. During
183
+ /// conversion, any `AttrTokenTree::AttrsTarget` gets "flattened" back to a
184
+ /// `TokenStream`, as described in the comment on
185
+ /// `attrs_and_tokens_to_token_trees`.
187
186
pub fn to_token_trees ( & self ) -> Vec < TokenTree > {
188
187
let mut res = Vec :: with_capacity ( self . 0 . len ( ) ) ;
189
188
for tree in self . 0 . iter ( ) {
@@ -200,59 +199,72 @@ impl AttrTokenStream {
200
199
) )
201
200
}
202
201
AttrTokenTree :: AttrsTarget ( target) => {
203
- let idx = target
204
- . attrs
205
- . partition_point ( |attr| matches ! ( attr. style, crate :: AttrStyle :: Outer ) ) ;
206
- let ( outer_attrs, inner_attrs) = target. attrs . split_at ( idx) ;
207
-
208
- let mut target_tokens = target. tokens . to_attr_token_stream ( ) . to_token_trees ( ) ;
209
- if !inner_attrs. is_empty ( ) {
210
- let mut found = false ;
211
- // Check the last two trees (to account for a trailing semi)
212
- for tree in target_tokens. iter_mut ( ) . rev ( ) . take ( 2 ) {
213
- if let TokenTree :: Delimited ( span, spacing, delim, delim_tokens) = tree {
214
- // Inner attributes are only supported on extern blocks, functions,
215
- // impls, and modules. All of these have their inner attributes
216
- // placed at the beginning of the rightmost outermost braced group:
217
- // e.g. fn foo() { #![my_attr] }
218
- //
219
- // Therefore, we can insert them back into the right location
220
- // without needing to do any extra position tracking.
221
- //
222
- // Note: Outline modules are an exception - they can
223
- // have attributes like `#![my_attr]` at the start of a file.
224
- // Support for custom attributes in this position is not
225
- // properly implemented - we always synthesize fake tokens,
226
- // so we never reach this code.
227
-
228
- let mut tts = vec ! [ ] ;
229
- for inner_attr in inner_attrs {
230
- tts. extend ( inner_attr. token_trees ( ) ) ;
231
- }
232
- tts. extend ( delim_tokens. 0 . iter ( ) . cloned ( ) ) ;
233
- let stream = TokenStream :: new ( tts) ;
234
- * tree = TokenTree :: Delimited ( * span, * spacing, * delim, stream) ;
235
- found = true ;
236
- break ;
237
- }
238
- }
239
-
240
- assert ! (
241
- found,
242
- "Failed to find trailing delimited group in: {target_tokens:?}"
243
- ) ;
244
- }
245
- for attr in outer_attrs {
246
- res. extend ( attr. token_trees ( ) ) ;
247
- }
248
- res. extend ( target_tokens) ;
202
+ attrs_and_tokens_to_token_trees ( & target. attrs , & target. tokens , & mut res) ;
249
203
}
250
204
}
251
205
}
252
206
res
253
207
}
254
208
}
255
209
210
+ // Converts multiple attributes and the tokens for a target AST node into token trees, and appends
211
+ // them to `res`.
212
+ //
213
+ // Example: if the AST node is "fn f() { blah(); }", then:
214
+ // - Simple if no attributes are present, e.g. "fn f() { blah(); }"
215
+ // - Simple if only outer attribute are present, e.g. "#[outer1] #[outer2] fn f() { blah(); }"
216
+ // - Trickier if inner attributes are present, because they must be moved within the AST node's
217
+ // tokens, e.g. "#[outer] fn f() { #![inner] blah() }"
218
+ fn attrs_and_tokens_to_token_trees (
219
+ attrs : & [ Attribute ] ,
220
+ target_tokens : & LazyAttrTokenStream ,
221
+ res : & mut Vec < TokenTree > ,
222
+ ) {
223
+ let idx = attrs. partition_point ( |attr| matches ! ( attr. style, crate :: AttrStyle :: Outer ) ) ;
224
+ let ( outer_attrs, inner_attrs) = attrs. split_at ( idx) ;
225
+
226
+ // Add outer attribute tokens.
227
+ for attr in outer_attrs {
228
+ res. extend ( attr. token_trees ( ) ) ;
229
+ }
230
+
231
+ // Add target AST node tokens.
232
+ res. extend ( target_tokens. to_attr_token_stream ( ) . to_token_trees ( ) ) ;
233
+
234
+ // Insert inner attribute tokens.
235
+ if !inner_attrs. is_empty ( ) {
236
+ let mut found = false ;
237
+ // Check the last two trees (to account for a trailing semi)
238
+ for tree in res. iter_mut ( ) . rev ( ) . take ( 2 ) {
239
+ if let TokenTree :: Delimited ( span, spacing, delim, delim_tokens) = tree {
240
+ // Inner attributes are only supported on extern blocks, functions,
241
+ // impls, and modules. All of these have their inner attributes
242
+ // placed at the beginning of the rightmost outermost braced group:
243
+ // e.g. fn foo() { #![my_attr] }
244
+ //
245
+ // Therefore, we can insert them back into the right location
246
+ // without needing to do any extra position tracking.
247
+ //
248
+ // Note: Outline modules are an exception - they can
249
+ // have attributes like `#![my_attr]` at the start of a file.
250
+ // Support for custom attributes in this position is not
251
+ // properly implemented - we always synthesize fake tokens,
252
+ // so we never reach this code.
253
+ let mut tts = vec ! [ ] ;
254
+ for inner_attr in inner_attrs {
255
+ tts. extend ( inner_attr. token_trees ( ) ) ;
256
+ }
257
+ tts. extend ( delim_tokens. 0 . iter ( ) . cloned ( ) ) ;
258
+ let stream = TokenStream :: new ( tts) ;
259
+ * tree = TokenTree :: Delimited ( * span, * spacing, * delim, stream) ;
260
+ found = true ;
261
+ break ;
262
+ }
263
+ }
264
+ assert ! ( found, "Failed to find trailing delimited group in: {res:?}" ) ;
265
+ }
266
+ }
267
+
256
268
/// Stores the tokens for an attribute target, along
257
269
/// with its attributes.
258
270
///
@@ -438,18 +450,10 @@ impl TokenStream {
438
450
}
439
451
440
452
pub fn from_ast ( node : & ( impl HasAttrs + HasTokens + fmt:: Debug ) ) -> TokenStream {
441
- let Some ( tokens) = node. tokens ( ) else {
442
- panic ! ( "missing tokens for node: {:?}" , node) ;
443
- } ;
444
- let attrs = node. attrs ( ) ;
445
- let attr_stream = if attrs. is_empty ( ) {
446
- tokens. to_attr_token_stream ( )
447
- } else {
448
- let target =
449
- AttrsTarget { attrs : attrs. iter ( ) . cloned ( ) . collect ( ) , tokens : tokens. clone ( ) } ;
450
- AttrTokenStream :: new ( vec ! [ AttrTokenTree :: AttrsTarget ( target) ] )
451
- } ;
452
- TokenStream :: new ( attr_stream. to_token_trees ( ) )
453
+ let tokens = node. tokens ( ) . unwrap_or_else ( || panic ! ( "missing tokens for node: {:?}" , node) ) ;
454
+ let mut tts = vec ! [ ] ;
455
+ attrs_and_tokens_to_token_trees ( node. attrs ( ) , tokens, & mut tts) ;
456
+ TokenStream :: new ( tts)
453
457
}
454
458
455
459
pub fn from_nonterminal_ast ( nt : & Nonterminal ) -> TokenStream {
0 commit comments