@@ -27,7 +27,7 @@ use std::{hash::Hash, iter, sync::Arc};
2727use base_db:: { impl_intern_key, salsa, CrateId , FileId , FileRange } ;
2828use syntax:: {
2929 algo:: skip_trivia_token,
30- ast:: { self , AstNode } ,
30+ ast:: { self , AstNode , AttrsOwner } ,
3131 Direction , SyntaxNode , SyntaxToken , TextRange , TextSize ,
3232} ;
3333
@@ -36,6 +36,7 @@ use crate::{
3636 builtin_attr:: BuiltinAttrExpander ,
3737 builtin_derive:: BuiltinDeriveExpander ,
3838 builtin_macro:: { BuiltinFnLikeExpander , EagerExpander } ,
39+ db:: TokenExpander ,
3940 proc_macro:: ProcMacroExpander ,
4041} ;
4142
@@ -132,6 +133,17 @@ impl HirFileId {
132133 } ;
133134 Some ( InFile :: new ( id. file_id , def_tt) )
134135 } ) ;
136+ let def_or_attr_input = def. or_else ( || match loc. kind {
137+ MacroCallKind :: Attr { ast_id, invoc_attr_index, .. } => {
138+ let tt = ast_id
139+ . to_node ( db)
140+ . attrs ( )
141+ . nth ( invoc_attr_index as usize )
142+ . and_then ( |attr| attr. token_tree ( ) ) ?;
143+ Some ( InFile :: new ( ast_id. file_id , tt) )
144+ }
145+ _ => None ,
146+ } ) ;
135147
136148 let macro_def = db. macro_def ( loc. def ) ?;
137149 let ( parse, exp_map) = db. parse_macro_expansion ( macro_file) . value ?;
@@ -140,7 +152,8 @@ impl HirFileId {
140152 Some ( ExpansionInfo {
141153 expanded : InFile :: new ( self , parse. syntax_node ( ) ) ,
142154 arg : InFile :: new ( loc. kind . file_id ( ) , arg_tt) ,
143- def,
155+ attr_input_or_mac_def : def_or_attr_input,
156+ macro_arg_shift : mbe:: Shift :: new ( & macro_arg. 0 ) ,
144157 macro_arg,
145158 macro_def,
146159 exp_map,
@@ -270,7 +283,7 @@ pub enum MacroCallKind {
270283 Attr {
271284 ast_id : AstId < ast:: Item > ,
272285 attr_name : String ,
273- attr_args : tt :: Subtree ,
286+ attr_args : mbe :: MappedSubTree ,
274287 /// Syntactical index of the invoking `#[attribute]`.
275288 ///
276289 /// Outer attributes are counted first, then inner attributes. This does not support
@@ -335,11 +348,12 @@ impl MacroCallId {
335348pub struct ExpansionInfo {
336349 expanded : InFile < SyntaxNode > ,
337350 arg : InFile < SyntaxNode > ,
338- /// The `macro_rules!` arguments.
339- def : Option < InFile < ast:: TokenTree > > ,
351+ /// The `macro_rules!` arguments or attribute input .
352+ attr_input_or_mac_def : Option < InFile < ast:: TokenTree > > ,
340353
341- macro_def : Arc < db :: TokenExpander > ,
354+ macro_def : Arc < TokenExpander > ,
342355 macro_arg : Arc < ( tt:: Subtree , mbe:: TokenMap ) > ,
356+ macro_arg_shift : mbe:: Shift ,
343357 exp_map : Arc < mbe:: TokenMap > ,
344358}
345359
@@ -350,11 +364,53 @@ impl ExpansionInfo {
350364 Some ( self . arg . with_value ( self . arg . value . parent ( ) ?) )
351365 }
352366
353- pub fn map_token_down ( & self , token : InFile < & SyntaxToken > ) -> Option < InFile < SyntaxToken > > {
367+ pub fn map_token_down (
368+ & self ,
369+ db : & dyn db:: AstDatabase ,
370+ item : Option < ast:: Item > ,
371+ token : InFile < & SyntaxToken > ,
372+ ) -> Option < InFile < SyntaxToken > > {
354373 assert_eq ! ( token. file_id, self . arg. file_id) ;
355- let range = token. value . text_range ( ) . checked_sub ( self . arg . value . text_range ( ) . start ( ) ) ?;
356- let token_id = self . macro_arg . 1 . token_by_range ( range) ?;
357- let token_id = self . macro_def . map_id_down ( token_id) ;
374+ let token_id = if let Some ( item) = item {
375+ let call_id = match self . expanded . file_id . 0 {
376+ HirFileIdRepr :: FileId ( _) => return None ,
377+ HirFileIdRepr :: MacroFile ( macro_file) => macro_file. macro_call_id ,
378+ } ;
379+ let loc = db. lookup_intern_macro ( call_id) ;
380+
381+ let token_range = token. value . text_range ( ) ;
382+ match & loc. kind {
383+ MacroCallKind :: Attr { attr_args, invoc_attr_index, .. } => {
384+ let attr = item. attrs ( ) . nth ( * invoc_attr_index as usize ) ?;
385+ match attr. token_tree ( ) {
386+ Some ( token_tree)
387+ if token_tree. syntax ( ) . text_range ( ) . contains_range ( token_range) =>
388+ {
389+ let attr_input_start =
390+ token_tree. left_delimiter_token ( ) ?. text_range ( ) . start ( ) ;
391+ let range = token. value . text_range ( ) . checked_sub ( attr_input_start) ?;
392+ let token_id =
393+ self . macro_arg_shift . shift ( attr_args. map . token_by_range ( range) ?) ;
394+ Some ( token_id)
395+ }
396+ _ => None ,
397+ }
398+ }
399+ _ => None ,
400+ }
401+ } else {
402+ None
403+ } ;
404+
405+ let token_id = match token_id {
406+ Some ( token_id) => token_id,
407+ None => {
408+ let range =
409+ token. value . text_range ( ) . checked_sub ( self . arg . value . text_range ( ) . start ( ) ) ?;
410+ let token_id = self . macro_arg . 1 . token_by_range ( range) ?;
411+ self . macro_def . map_id_down ( token_id)
412+ }
413+ } ;
358414
359415 let range = self . exp_map . range_by_token ( token_id, token. value . kind ( ) ) ?;
360416
@@ -365,20 +421,36 @@ impl ExpansionInfo {
365421
366422 pub fn map_token_up (
367423 & self ,
424+ db : & dyn db:: AstDatabase ,
368425 token : InFile < & SyntaxToken > ,
369426 ) -> Option < ( InFile < SyntaxToken > , Origin ) > {
370427 let token_id = self . exp_map . token_by_range ( token. value . text_range ( ) ) ?;
428+ let ( mut token_id, origin) = self . macro_def . map_id_up ( token_id) ;
371429
372- let ( token_id, origin) = self . macro_def . map_id_up ( token_id) ;
373- let ( token_map, tt) = match origin {
374- mbe:: Origin :: Call => ( & self . macro_arg . 1 , self . arg . clone ( ) ) ,
375- mbe:: Origin :: Def => match ( & * self . macro_def , self . def . as_ref ( ) ) {
376- (
377- db:: TokenExpander :: MacroRules { def_site_token_map, .. }
378- | db:: TokenExpander :: MacroDef { def_site_token_map, .. } ,
379- Some ( tt) ,
380- ) => ( def_site_token_map, tt. syntax ( ) . cloned ( ) ) ,
381- _ => panic ! ( "`Origin::Def` used with non-`macro_rules!` macro" ) ,
430+ let call_id = match self . expanded . file_id . 0 {
431+ HirFileIdRepr :: FileId ( _) => return None ,
432+ HirFileIdRepr :: MacroFile ( macro_file) => macro_file. macro_call_id ,
433+ } ;
434+ let loc = db. lookup_intern_macro ( call_id) ;
435+
436+ let ( token_map, tt) = match & loc. kind {
437+ MacroCallKind :: Attr { attr_args, .. } => match self . macro_arg_shift . unshift ( token_id) {
438+ Some ( unshifted) => {
439+ token_id = unshifted;
440+ ( & attr_args. map , self . attr_input_or_mac_def . clone ( ) ?. syntax ( ) . cloned ( ) )
441+ }
442+ None => ( & self . macro_arg . 1 , self . arg . clone ( ) ) ,
443+ } ,
444+ _ => match origin {
445+ mbe:: Origin :: Call => ( & self . macro_arg . 1 , self . arg . clone ( ) ) ,
446+ mbe:: Origin :: Def => match ( & * self . macro_def , self . attr_input_or_mac_def . as_ref ( ) ) {
447+ (
448+ TokenExpander :: MacroRules { def_site_token_map, .. }
449+ | TokenExpander :: MacroDef { def_site_token_map, .. } ,
450+ Some ( tt) ,
451+ ) => ( def_site_token_map, tt. syntax ( ) . cloned ( ) ) ,
452+ _ => panic ! ( "`Origin::Def` used with non-`macro_rules!` macro" ) ,
453+ } ,
382454 } ,
383455 } ;
384456
@@ -532,7 +604,7 @@ fn ascend_call_token(
532604 expansion : & ExpansionInfo ,
533605 token : InFile < SyntaxToken > ,
534606) -> Option < InFile < SyntaxToken > > {
535- let ( mapped, origin) = expansion. map_token_up ( token. as_ref ( ) ) ?;
607+ let ( mapped, origin) = expansion. map_token_up ( db , token. as_ref ( ) ) ?;
536608 if origin != Origin :: Call {
537609 return None ;
538610 }
0 commit comments