@@ -241,19 +241,26 @@ fn traverse(
241
241
current_macro = Some ( mac. into ( ) ) ;
242
242
continue ;
243
243
}
244
- Some ( item) if sema. is_attr_macro_call ( & item) => current_attr_call = Some ( item) ,
245
- Some ( item) if current_attr_call. is_none ( ) => {
246
- let adt = match item {
247
- ast:: Item :: Enum ( it) => Some ( ast:: Adt :: Enum ( it) ) ,
248
- ast:: Item :: Struct ( it) => Some ( ast:: Adt :: Struct ( it) ) ,
249
- ast:: Item :: Union ( it) => Some ( ast:: Adt :: Union ( it) ) ,
250
- _ => None ,
251
- } ;
252
- match adt {
253
- Some ( adt) if sema. is_derive_annotated ( & adt) => {
254
- current_derive_call = Some ( ast:: Item :: from ( adt) ) ;
244
+ Some ( item) => {
245
+ if matches ! ( node. kind( ) , FN | CONST | STATIC ) {
246
+ bindings_shadow_count. clear ( ) ;
247
+ }
248
+
249
+ if sema. is_attr_macro_call ( & item) {
250
+ current_attr_call = Some ( item) ;
251
+ } else if current_attr_call. is_none ( ) {
252
+ let adt = match item {
253
+ ast:: Item :: Enum ( it) => Some ( ast:: Adt :: Enum ( it) ) ,
254
+ ast:: Item :: Struct ( it) => Some ( ast:: Adt :: Struct ( it) ) ,
255
+ ast:: Item :: Union ( it) => Some ( ast:: Adt :: Union ( it) ) ,
256
+ _ => None ,
257
+ } ;
258
+ match adt {
259
+ Some ( adt) if sema. is_derive_annotated ( & adt) => {
260
+ current_derive_call = Some ( ast:: Item :: from ( adt) ) ;
261
+ }
262
+ _ => ( ) ,
255
263
}
256
- _ => ( ) ,
257
264
}
258
265
}
259
266
None if ast:: Attr :: can_cast ( node. kind ( ) ) => inside_attribute = true ,
@@ -291,6 +298,8 @@ fn traverse(
291
298
WalkEvent :: Enter ( it) => it,
292
299
WalkEvent :: Leave ( NodeOrToken :: Token ( _) ) => continue ,
293
300
WalkEvent :: Leave ( NodeOrToken :: Node ( node) ) => {
301
+ // Doc comment highlighting injection, we do this when leaving the node
302
+ // so that we overwrite the highlighting of the doc comment itself.
294
303
inject:: doc_comment ( hl, sema, InFile :: new ( file_id. into ( ) , & node) ) ;
295
304
continue ;
296
305
}
@@ -302,57 +311,68 @@ fn traverse(
302
311
}
303
312
}
304
313
305
- // only attempt to descend if we are inside a macro call or attribute
306
- // as calling `descend_into_macros_single` gets rather expensive if done for every single token
307
- // additionally, do not descend into comments, descending maps down to doc attributes which get
308
- // tagged as string literals.
309
- let descend_token = ( current_macro_call. is_some ( )
310
- || current_attr_call. is_some ( )
311
- || current_derive_call. is_some ( ) )
312
- && element. kind ( ) != COMMENT ;
313
- let element_to_highlight = if descend_token {
314
- let token = match & element {
315
- NodeOrToken :: Node ( _) => continue ,
316
- NodeOrToken :: Token ( tok) => tok. clone ( ) ,
317
- } ;
318
- let in_mcall_outside_tt = current_attr_call. is_none ( )
319
- && token. parent ( ) . as_ref ( ) . map ( SyntaxNode :: kind) != Some ( TOKEN_TREE ) ;
320
- let token = match in_mcall_outside_tt {
321
- // not in the macros/derives token tree, don't attempt to descend
322
- true => token,
323
- false => sema. descend_into_macros_single ( token) ,
324
- } ;
325
- match token. parent ( ) {
326
- Some ( parent) => {
327
- // Names and NameRefs have special semantics, use them instead of the tokens
328
- // as otherwise we won't ever visit them
329
- match ( token. kind ( ) , parent. kind ( ) ) {
330
- ( T ! [ ident] , NAME | NAME_REF ) => parent. into ( ) ,
331
- ( T ! [ self ] | T ! [ super ] | T ! [ crate ] | T ! [ Self ] , NAME_REF ) => parent. into ( ) ,
332
- ( INT_NUMBER , NAME_REF ) => parent. into ( ) ,
333
- ( LIFETIME_IDENT , LIFETIME ) => parent. into ( ) ,
334
- _ => token. into ( ) ,
314
+ let element = match element. clone ( ) {
315
+ NodeOrToken :: Node ( n) => match ast:: NameLike :: cast ( n) {
316
+ Some ( n) => NodeOrToken :: Node ( n) ,
317
+ None => continue ,
318
+ } ,
319
+ NodeOrToken :: Token ( t) => NodeOrToken :: Token ( t) ,
320
+ } ;
321
+ let token = element. as_token ( ) . cloned ( ) ;
322
+
323
+ // Descending tokens into macros is expensive even if no descending occurs, so make sure
324
+ // that we actually are in a position where descending is possible.
325
+ let in_macro = current_macro_call. is_some ( )
326
+ || current_derive_call. is_some ( )
327
+ || current_attr_call. is_some ( ) ;
328
+ let descended_element = if in_macro {
329
+ // Attempt to descend tokens into macro-calls.
330
+ match element {
331
+ NodeOrToken :: Token ( token) if token. kind ( ) != COMMENT => {
332
+ // For function-like macro calls and derive attributes, only attempt to descend if
333
+ // we are inside their token-trees.
334
+ let in_tt = current_attr_call. is_some ( )
335
+ || token. parent ( ) . as_ref ( ) . map ( SyntaxNode :: kind) == Some ( TOKEN_TREE ) ;
336
+
337
+ if in_tt {
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 ) => {
344
+ NodeOrToken :: Node ( parent)
345
+ }
346
+ ( T ! [ self ] | T ! [ super ] | T ! [ crate ] | T ! [ Self ] , NAME_REF ) => {
347
+ NodeOrToken :: Node ( parent)
348
+ }
349
+ ( INT_NUMBER , NAME_REF ) => NodeOrToken :: Node ( parent) ,
350
+ ( LIFETIME_IDENT , LIFETIME ) => NodeOrToken :: Node ( parent) ,
351
+ _ => NodeOrToken :: Token ( token) ,
352
+ } ,
353
+ None => NodeOrToken :: Token ( token) ,
354
+ }
355
+ } else {
356
+ NodeOrToken :: Token ( token)
335
357
}
336
358
}
337
- None => token . into ( ) ,
359
+ e => e ,
338
360
}
339
361
} else {
340
- element. clone ( )
362
+ element
341
363
} ;
342
364
343
365
// FIXME: do proper macro def highlighting https://github.com/rust-analyzer/rust-analyzer/issues/6232
344
366
// Skip metavariables from being highlighted to prevent keyword highlighting in them
345
- if macro_highlighter. highlight ( & element_to_highlight ) . is_some ( ) {
367
+ if descended_element . as_token ( ) . and_then ( |t| macro_highlighter. highlight ( t ) ) . is_some ( ) {
346
368
continue ;
347
369
}
348
370
349
371
// string highlight injections, note this does not use the descended element as proc-macros
350
372
// can rewrite string literals which invalidates our indices
351
- if let ( Some ( token) , Some ( token_to_highlight) ) =
352
- ( element. into_token ( ) , element_to_highlight. as_token ( ) )
353
- {
373
+ if let ( Some ( token) , Some ( descended_token) ) = ( token, descended_element. as_token ( ) ) {
354
374
let string = ast:: String :: cast ( token) ;
355
- let string_to_highlight = ast:: String :: cast ( token_to_highlight . clone ( ) ) ;
375
+ let string_to_highlight = ast:: String :: cast ( descended_token . clone ( ) ) ;
356
376
if let Some ( ( string, expanded_string) ) = string. zip ( string_to_highlight) {
357
377
if string. is_raw ( ) {
358
378
if inject:: ra_fixture ( hl, sema, & string, & expanded_string) . is_some ( ) {
@@ -377,14 +397,13 @@ fn traverse(
377
397
}
378
398
}
379
399
380
- // do the normal highlighting
381
- let element = match element_to_highlight {
382
- NodeOrToken :: Node ( node) => highlight:: node (
400
+ let element = match descended_element {
401
+ NodeOrToken :: Node ( name_like) => highlight:: name_like (
383
402
sema,
384
403
krate,
385
404
& mut bindings_shadow_count,
386
405
syntactic_name_ref_highlighting,
387
- node ,
406
+ name_like ,
388
407
) ,
389
408
NodeOrToken :: Token ( token) => highlight:: token ( sema, token) . zip ( Some ( None ) ) ,
390
409
} ;
0 commit comments