@@ -206,18 +206,19 @@ fn traverse(
206
206
let is_unlinked = sema. to_module_def ( file_id) . is_none ( ) ;
207
207
let mut bindings_shadow_count: FxHashMap < Name , u32 > = FxHashMap :: default ( ) ;
208
208
209
- let mut current_macro_call: Option < ast:: MacroCall > = None ;
210
- let mut current_attr_call = None ;
211
- let mut current_derive_call = None ;
209
+ let mut tt_level = 0 ;
210
+ let mut attr_or_derive_item = None ;
212
211
let mut current_macro: Option < ast:: Macro > = None ;
213
212
let mut macro_highlighter = MacroHighlighter :: default ( ) ;
214
213
let mut inside_attribute = false ;
215
214
216
215
// Walk all nodes, keeping track of whether we are inside a macro or not.
217
216
// If in macro, expand it first and highlight the expanded code.
218
217
for event in root. preorder_with_tokens ( ) {
218
+ use WalkEvent :: { Enter , Leave } ;
219
+
219
220
let range = match & event {
220
- WalkEvent :: Enter ( it) | WalkEvent :: Leave ( it) => it. text_range ( ) ,
221
+ Enter ( it) | Leave ( it) => it. text_range ( ) ,
221
222
} ;
222
223
223
224
// Element outside of the viewport, no need to highlight
@@ -227,78 +228,84 @@ fn traverse(
227
228
228
229
// set macro and attribute highlighting states
229
230
match event. clone ( ) {
230
- WalkEvent :: Enter ( NodeOrToken :: Node ( node) ) => match ast:: Item :: cast ( node. clone ( ) ) {
231
- Some ( ast:: Item :: MacroCall ( mcall) ) => {
232
- current_macro_call = Some ( mcall) ;
233
- continue ;
234
- }
235
- Some ( ast:: Item :: MacroRules ( mac) ) => {
236
- macro_highlighter. init ( ) ;
237
- current_macro = Some ( mac. into ( ) ) ;
238
- continue ;
239
- }
240
- Some ( ast:: Item :: MacroDef ( mac) ) => {
241
- macro_highlighter. init ( ) ;
242
- current_macro = Some ( mac. into ( ) ) ;
243
- continue ;
244
- }
245
- Some ( item) => {
246
- if matches ! ( node. kind( ) , FN | CONST | STATIC ) {
247
- bindings_shadow_count. clear ( ) ;
231
+ Enter ( NodeOrToken :: Node ( node) ) if ast:: TokenTree :: can_cast ( node. kind ( ) ) => {
232
+ tt_level += 1 ;
233
+ }
234
+ Leave ( NodeOrToken :: Node ( node) ) if ast:: TokenTree :: can_cast ( node. kind ( ) ) => {
235
+ tt_level -= 1 ;
236
+ }
237
+ Enter ( NodeOrToken :: Node ( node) ) if ast:: Attr :: can_cast ( node. kind ( ) ) => {
238
+ inside_attribute = true
239
+ }
240
+ Leave ( NodeOrToken :: Node ( node) ) if ast:: Attr :: can_cast ( node. kind ( ) ) => {
241
+ inside_attribute = false
242
+ }
243
+
244
+ Enter ( NodeOrToken :: Node ( node) ) if ast:: Item :: can_cast ( node. kind ( ) ) => {
245
+ match ast:: Item :: cast ( node. clone ( ) ) {
246
+ Some ( ast:: Item :: MacroRules ( mac) ) => {
247
+ macro_highlighter. init ( ) ;
248
+ current_macro = Some ( mac. into ( ) ) ;
249
+ continue ;
248
250
}
251
+ Some ( ast:: Item :: MacroDef ( mac) ) => {
252
+ macro_highlighter. init ( ) ;
253
+ current_macro = Some ( mac. into ( ) ) ;
254
+ continue ;
255
+ }
256
+ Some ( item) => {
257
+ if matches ! ( node. kind( ) , FN | CONST | STATIC ) {
258
+ bindings_shadow_count. clear ( ) ;
259
+ }
249
260
250
- if sema. is_attr_macro_call ( & item) {
251
- current_attr_call = Some ( item) ;
252
- } else if current_attr_call. is_none ( ) {
253
- let adt = match item {
254
- ast:: Item :: Enum ( it) => Some ( ast:: Adt :: Enum ( it) ) ,
255
- ast:: Item :: Struct ( it) => Some ( ast:: Adt :: Struct ( it) ) ,
256
- ast:: Item :: Union ( it) => Some ( ast:: Adt :: Union ( it) ) ,
257
- _ => None ,
258
- } ;
259
- match adt {
260
- Some ( adt) if sema. is_derive_annotated ( & adt) => {
261
- current_derive_call = Some ( ast:: Item :: from ( adt) ) ;
261
+ if attr_or_derive_item. is_none ( ) {
262
+ if sema. is_attr_macro_call ( & item) {
263
+ attr_or_derive_item = Some ( item) ;
264
+ } else {
265
+ let adt = match item {
266
+ ast:: Item :: Enum ( it) => Some ( ast:: Adt :: Enum ( it) ) ,
267
+ ast:: Item :: Struct ( it) => Some ( ast:: Adt :: Struct ( it) ) ,
268
+ ast:: Item :: Union ( it) => Some ( ast:: Adt :: Union ( it) ) ,
269
+ _ => None ,
270
+ } ;
271
+ match adt {
272
+ Some ( adt) if sema. is_derive_annotated ( & adt) => {
273
+ attr_or_derive_item = Some ( ast:: Item :: from ( adt) ) ;
274
+ }
275
+ _ => ( ) ,
276
+ }
262
277
}
263
- _ => ( ) ,
264
278
}
265
279
}
280
+ _ => ( ) ,
266
281
}
267
- None if ast:: Attr :: can_cast ( node. kind ( ) ) => inside_attribute = true ,
268
- _ => ( ) ,
269
- } ,
270
- WalkEvent :: Leave ( NodeOrToken :: Node ( node) ) => match ast:: Item :: cast ( node. clone ( ) ) {
271
- Some ( ast:: Item :: MacroCall ( mcall) ) => {
272
- assert_eq ! ( current_macro_call, Some ( mcall) ) ;
273
- current_macro_call = None ;
274
- }
275
- Some ( ast:: Item :: MacroRules ( mac) ) => {
276
- assert_eq ! ( current_macro, Some ( mac. into( ) ) ) ;
277
- current_macro = None ;
278
- macro_highlighter = MacroHighlighter :: default ( ) ;
279
- }
280
- Some ( ast:: Item :: MacroDef ( mac) ) => {
281
- assert_eq ! ( current_macro, Some ( mac. into( ) ) ) ;
282
- current_macro = None ;
283
- macro_highlighter = MacroHighlighter :: default ( ) ;
284
- }
285
- Some ( item) if current_attr_call. as_ref ( ) . map_or ( false , |it| * it == item) => {
286
- current_attr_call = None ;
287
- }
288
- Some ( item) if current_derive_call. as_ref ( ) . map_or ( false , |it| * it == item) => {
289
- current_derive_call = None ;
282
+ }
283
+ Leave ( NodeOrToken :: Node ( node) ) if ast:: Item :: can_cast ( node. kind ( ) ) => {
284
+ match ast:: Item :: cast ( node. clone ( ) ) {
285
+ Some ( ast:: Item :: MacroRules ( mac) ) => {
286
+ assert_eq ! ( current_macro, Some ( mac. into( ) ) ) ;
287
+ current_macro = None ;
288
+ macro_highlighter = MacroHighlighter :: default ( ) ;
289
+ }
290
+ Some ( ast:: Item :: MacroDef ( mac) ) => {
291
+ assert_eq ! ( current_macro, Some ( mac. into( ) ) ) ;
292
+ current_macro = None ;
293
+ macro_highlighter = MacroHighlighter :: default ( ) ;
294
+ }
295
+ Some ( item) if attr_or_derive_item. as_ref ( ) . map_or ( false , |it| * it == item) => {
296
+ attr_or_derive_item = None ;
297
+ }
298
+ _ => ( ) ,
290
299
}
291
- None if ast:: Attr :: can_cast ( node. kind ( ) ) => inside_attribute = false ,
292
- _ => ( ) ,
293
- } ,
300
+ }
294
301
_ => ( ) ,
295
302
}
296
303
297
304
let element = match event {
298
- WalkEvent :: Enter ( NodeOrToken :: Token ( tok) ) if tok. kind ( ) == WHITESPACE => continue ,
299
- WalkEvent :: Enter ( it) => it,
300
- WalkEvent :: Leave ( NodeOrToken :: Token ( _) ) => continue ,
301
- WalkEvent :: Leave ( NodeOrToken :: Node ( node) ) => {
305
+ Enter ( NodeOrToken :: Token ( tok) ) if tok. kind ( ) == WHITESPACE => continue ,
306
+ Enter ( it) => it,
307
+ Leave ( NodeOrToken :: Token ( _) ) => continue ,
308
+ Leave ( NodeOrToken :: Node ( node) ) => {
302
309
// Doc comment highlighting injection, we do this when leaving the node
303
310
// so that we overwrite the highlighting of the doc comment itself.
304
311
inject:: doc_comment ( hl, sema, InFile :: new ( file_id. into ( ) , & node) ) ;
@@ -323,38 +330,25 @@ fn traverse(
323
330
324
331
// Descending tokens into macros is expensive even if no descending occurs, so make sure
325
332
// that we actually are in a position where descending is possible.
326
- let in_macro = current_macro_call. is_some ( )
327
- || current_derive_call. is_some ( )
328
- || current_attr_call. is_some ( ) ;
333
+ let in_macro = tt_level > 0 || attr_or_derive_item. is_some ( ) ;
329
334
let descended_element = if in_macro {
330
335
// Attempt to descend tokens into macro-calls.
331
336
match element {
332
337
NodeOrToken :: Token ( token) if token. kind ( ) != COMMENT => {
333
- // For function-like macro calls and derive attributes, only attempt to descend if
334
- // we are inside their token-trees.
335
- let in_tt = current_attr_call. is_some ( )
336
- || token. parent ( ) . as_ref ( ) . map ( SyntaxNode :: kind) == Some ( TOKEN_TREE ) ;
337
-
338
- if in_tt {
339
- let token = sema. descend_into_macros_single ( token) ;
340
- match token. parent ( ) . and_then ( ast:: NameLike :: cast) {
341
- // Remap the token into the wrapping single token nodes
342
- // FIXME: if the node doesn't resolve, we also won't do token based highlighting!
343
- Some ( parent) => match ( token. kind ( ) , parent. syntax ( ) . kind ( ) ) {
344
- ( T ! [ self ] | T ! [ ident] , NAME | NAME_REF ) => {
345
- NodeOrToken :: Node ( parent)
346
- }
347
- ( T ! [ self ] | T ! [ super ] | T ! [ crate ] | T ! [ Self ] , NAME_REF ) => {
348
- NodeOrToken :: Node ( parent)
349
- }
350
- ( INT_NUMBER , NAME_REF ) => NodeOrToken :: Node ( parent) ,
351
- ( LIFETIME_IDENT , LIFETIME ) => NodeOrToken :: Node ( parent) ,
352
- _ => NodeOrToken :: Token ( token) ,
353
- } ,
354
- None => NodeOrToken :: Token ( token) ,
355
- }
356
- } else {
357
- NodeOrToken :: Token ( token)
338
+ let token = sema. descend_into_macros_single ( token) ;
339
+ match token. parent ( ) . and_then ( ast:: NameLike :: cast) {
340
+ // Remap the token into the wrapping single token nodes
341
+ // FIXME: if the node doesn't resolve, we also won't do token based highlighting!
342
+ Some ( parent) => match ( token. kind ( ) , parent. syntax ( ) . kind ( ) ) {
343
+ ( T ! [ self ] | T ! [ ident] , NAME | NAME_REF ) => NodeOrToken :: Node ( parent) ,
344
+ ( T ! [ self ] | T ! [ super ] | T ! [ crate ] | T ! [ Self ] , NAME_REF ) => {
345
+ NodeOrToken :: Node ( parent)
346
+ }
347
+ ( INT_NUMBER , NAME_REF ) => NodeOrToken :: Node ( parent) ,
348
+ ( LIFETIME_IDENT , LIFETIME ) => NodeOrToken :: Node ( parent) ,
349
+ _ => NodeOrToken :: Token ( token) ,
350
+ } ,
351
+ None => NodeOrToken :: Token ( token) ,
358
352
}
359
353
}
360
354
e => e,
0 commit comments