@@ -350,6 +350,53 @@ impl MacroCallKind {
350
350
}
351
351
}
352
352
353
+ /// Returns the original file range that best describes the location of this macro call.
354
+ ///
355
+ /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
356
+ /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
357
+ /// get only the specific derive that is being referred to.
358
+ pub fn original_call_range ( self , db : & dyn db:: AstDatabase ) -> FileRange {
359
+ let mut kind = self ;
360
+ loop {
361
+ match kind. file_id ( ) . 0 {
362
+ HirFileIdRepr :: MacroFile ( file) => {
363
+ kind = db. lookup_intern_macro_call ( file. macro_call_id ) . kind ;
364
+ }
365
+ _ => break ,
366
+ }
367
+ }
368
+
369
+ // `call_id` is now the outermost macro call, so its location is in a real file.
370
+ let file_id = match kind. file_id ( ) . 0 {
371
+ HirFileIdRepr :: FileId ( it) => it,
372
+ HirFileIdRepr :: MacroFile ( _) => unreachable ! ( "encountered unexpected macro file" ) ,
373
+ } ;
374
+ let range = match kind {
375
+ MacroCallKind :: FnLike { ast_id, .. } => ast_id. to_node ( db) . syntax ( ) . text_range ( ) ,
376
+ MacroCallKind :: Derive { ast_id, derive_attr_index, .. } => {
377
+ // FIXME: should be the range of the macro name, not the whole derive
378
+ ast_id
379
+ . to_node ( db)
380
+ . doc_comments_and_attrs ( )
381
+ . nth ( derive_attr_index as usize )
382
+ . expect ( "missing derive" )
383
+ . expect_right ( "derive is a doc comment?" )
384
+ . syntax ( )
385
+ . text_range ( )
386
+ }
387
+ MacroCallKind :: Attr { ast_id, invoc_attr_index, .. } => ast_id
388
+ . to_node ( db)
389
+ . doc_comments_and_attrs ( )
390
+ . nth ( invoc_attr_index as usize )
391
+ . expect ( "missing attribute" )
392
+ . expect_right ( "attribute macro is a doc comment?" )
393
+ . syntax ( )
394
+ . text_range ( ) ,
395
+ } ;
396
+
397
+ FileRange { range, file_id }
398
+ }
399
+
353
400
fn arg ( & self , db : & dyn db:: AstDatabase ) -> Option < SyntaxNode > {
354
401
match self {
355
402
MacroCallKind :: FnLike { ast_id, .. } => {
@@ -623,15 +670,13 @@ impl<'a> InFile<&'a SyntaxNode> {
623
670
}
624
671
625
672
// Fall back to whole macro call.
626
- let mut node = self . cloned ( ) ;
627
- while let Some ( call_node) = node. file_id . call_node ( db) {
628
- node = call_node;
673
+ match self . file_id . 0 {
674
+ HirFileIdRepr :: FileId ( file_id) => FileRange { file_id, range : self . value . text_range ( ) } ,
675
+ HirFileIdRepr :: MacroFile ( mac_file) => {
676
+ let loc = db. lookup_intern_macro_call ( mac_file. macro_call_id ) ;
677
+ loc. kind . original_call_range ( db)
678
+ }
629
679
}
630
-
631
- let orig_file = node. file_id . original_file ( db) ;
632
- assert_eq ! ( node. file_id, orig_file. into( ) ) ;
633
-
634
- FileRange { file_id : orig_file, range : node. value . text_range ( ) }
635
680
}
636
681
637
682
/// Attempts to map the syntax node back up its macro calls.
0 commit comments