@@ -117,6 +117,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
117117 pub fn expand ( & self , macro_call : & ast:: MacroCall ) -> Option < SyntaxNode > {
118118 self . imp . expand ( macro_call)
119119 }
120+
121+ /// If `item` has an attribute macro attached to it, expands it.
122+ pub fn expand_attr_macro ( & self , item : & ast:: Item ) -> Option < SyntaxNode > {
123+ self . imp . expand_attr_macro ( item)
124+ }
125+
126+ pub fn is_attr_macro_call ( & self , item : & ast:: Item ) -> bool {
127+ self . imp . is_attr_macro_call ( item)
128+ }
129+
120130 pub fn speculative_expand (
121131 & self ,
122132 actual_macro_call : & ast:: MacroCall ,
@@ -332,6 +342,22 @@ impl<'db> SemanticsImpl<'db> {
332342 Some ( node)
333343 }
334344
345+ fn expand_attr_macro ( & self , item : & ast:: Item ) -> Option < SyntaxNode > {
346+ let sa = self . analyze ( item. syntax ( ) ) ;
347+ let src = InFile :: new ( sa. file_id , item. clone ( ) ) ;
348+ let macro_call_id = self . with_ctx ( |ctx| ctx. item_to_macro_call ( src) ) ?;
349+ let file_id = macro_call_id. as_file ( ) ;
350+ let node = self . db . parse_or_expand ( file_id) ?;
351+ self . cache ( node. clone ( ) , file_id) ;
352+ Some ( node)
353+ }
354+
355+ fn is_attr_macro_call ( & self , item : & ast:: Item ) -> bool {
356+ let sa = self . analyze ( item. syntax ( ) ) ;
357+ let src = InFile :: new ( sa. file_id , item. clone ( ) ) ;
358+ self . with_ctx ( |ctx| ctx. item_to_macro_call ( src) . is_some ( ) )
359+ }
360+
335361 fn speculative_expand (
336362 & self ,
337363 actual_macro_call : & ast:: MacroCall ,
@@ -362,25 +388,57 @@ impl<'db> SemanticsImpl<'db> {
362388
363389 let token = successors ( Some ( InFile :: new ( sa. file_id , token) ) , |token| {
364390 self . db . unwind_if_cancelled ( ) ;
365- let macro_call = token. value . ancestors ( ) . find_map ( ast:: MacroCall :: cast) ?;
366- let tt = macro_call. token_tree ( ) ?;
367- if !tt. syntax ( ) . text_range ( ) . contains_range ( token. value . text_range ( ) ) {
368- return None ;
369- }
370- let file_id = sa. expand ( self . db , token. with_value ( & macro_call) ) ?;
371- let token = self
372- . expansion_info_cache
373- . borrow_mut ( )
374- . entry ( file_id)
375- . or_insert_with ( || file_id. expansion_info ( self . db . upcast ( ) ) )
376- . as_ref ( ) ?
377- . map_token_down ( token. as_ref ( ) ) ?;
378-
379- if let Some ( parent) = token. value . parent ( ) {
380- self . cache ( find_root ( & parent) , token. file_id ) ;
391+
392+ for node in token. value . ancestors ( ) {
393+ match_ast ! {
394+ match node {
395+ ast:: MacroCall ( macro_call) => {
396+ let tt = macro_call. token_tree( ) ?;
397+ if !tt. syntax( ) . text_range( ) . contains_range( token. value. text_range( ) ) {
398+ return None ;
399+ }
400+ let file_id = sa. expand( self . db, token. with_value( & macro_call) ) ?;
401+ let token = self
402+ . expansion_info_cache
403+ . borrow_mut( )
404+ . entry( file_id)
405+ . or_insert_with( || file_id. expansion_info( self . db. upcast( ) ) )
406+ . as_ref( ) ?
407+ . map_token_down( token. as_ref( ) ) ?;
408+
409+ if let Some ( parent) = token. value. parent( ) {
410+ self . cache( find_root( & parent) , token. file_id) ;
411+ }
412+
413+ return Some ( token) ;
414+ } ,
415+ ast:: Item ( item) => {
416+ match self . with_ctx( |ctx| ctx. item_to_macro_call( token. with_value( item) ) ) {
417+ Some ( call_id) => {
418+ let file_id = call_id. as_file( ) ;
419+ let token = self
420+ . expansion_info_cache
421+ . borrow_mut( )
422+ . entry( file_id)
423+ . or_insert_with( || file_id. expansion_info( self . db. upcast( ) ) )
424+ . as_ref( ) ?
425+ . map_token_down( token. as_ref( ) ) ?;
426+
427+ if let Some ( parent) = token. value. parent( ) {
428+ self . cache( find_root( & parent) , token. file_id) ;
429+ }
430+
431+ return Some ( token) ;
432+ }
433+ None => { }
434+ }
435+ } ,
436+ _ => { }
437+ }
438+ }
381439 }
382440
383- Some ( token )
441+ None
384442 } )
385443 . last ( )
386444 . unwrap ( ) ;
0 commit comments