@@ -19,7 +19,7 @@ use std::{iter, ops::Range, sync};
1919use base_db:: RootQueryDb ;
2020use expect_test:: Expect ;
2121use hir_expand:: {
22- InFile , MacroCallKind , MacroKind ,
22+ AstId , InFile , MacroCallId , MacroCallKind , MacroKind ,
2323 db:: ExpandDatabase ,
2424 proc_macro:: { ProcMacro , ProcMacroExpander , ProcMacroExpansionError , ProcMacroKind } ,
2525 span_map:: SpanMapRef ,
@@ -29,18 +29,17 @@ use itertools::Itertools;
2929use span:: { Edition , Span } ;
3030use stdx:: { format_to, format_to_acc} ;
3131use syntax:: {
32- AstNode ,
32+ AstNode , AstPtr ,
3333 SyntaxKind :: { COMMENT , EOF , IDENT , LIFETIME_IDENT } ,
3434 SyntaxNode , T ,
3535 ast:: { self , edit:: IndentLevel } ,
3636} ;
3737use test_fixture:: WithFixture ;
3838
3939use crate :: {
40- AdtId , AsMacroCall , Lookup , ModuleDefId ,
40+ AdtId , Lookup , ModuleDefId ,
4141 db:: DefDatabase ,
42- nameres:: { DefMap , MacroSubNs , ModuleSource } ,
43- resolver:: HasResolver ,
42+ nameres:: { DefMap , ModuleSource } ,
4443 src:: HasSource ,
4544 test_db:: TestDB ,
4645 tt:: TopSubtree ,
@@ -78,7 +77,6 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
7877 expect. assert_eq ( & errors) ;
7978}
8079
81- #[ track_caller]
8280fn check ( #[ rust_analyzer:: rust_fixture] ra_fixture : & str , mut expect : Expect ) {
8381 let extra_proc_macros = vec ! [ (
8482 r#"
@@ -95,54 +93,59 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
9593 disabled: false ,
9694 } ,
9795 ) ] ;
96+
97+ fn resolve (
98+ db : & dyn DefDatabase ,
99+ def_map : & DefMap ,
100+ ast_id : AstId < ast:: MacroCall > ,
101+ ast_ptr : InFile < AstPtr < ast:: MacroCall > > ,
102+ ) -> Option < MacroCallId > {
103+ def_map. modules ( ) . find_map ( |module| {
104+ for decl in
105+ module. 1 . scope . declarations ( ) . chain ( module. 1 . scope . unnamed_consts ( ) . map ( Into :: into) )
106+ {
107+ let body = match decl {
108+ ModuleDefId :: FunctionId ( it) => it. into ( ) ,
109+ ModuleDefId :: ConstId ( it) => it. into ( ) ,
110+ ModuleDefId :: StaticId ( it) => it. into ( ) ,
111+ _ => continue ,
112+ } ;
113+
114+ let ( body, sm) = db. body_with_source_map ( body) ;
115+ if let Some ( it) =
116+ body. blocks ( db) . find_map ( |block| resolve ( db, & block. 1 , ast_id, ast_ptr) )
117+ {
118+ return Some ( it) ;
119+ }
120+ if let Some ( ( _, res) ) = sm. macro_calls ( ) . find ( |it| it. 0 == ast_ptr) {
121+ return Some ( res) ;
122+ }
123+ }
124+ module. 1 . scope . macro_invoc ( ast_id)
125+ } )
126+ }
127+
98128 let db = TestDB :: with_files_extra_proc_macros ( ra_fixture, extra_proc_macros) ;
99129 let krate = db. fetch_test_crate ( ) ;
100130 let def_map = db. crate_def_map ( krate) ;
101131 let local_id = DefMap :: ROOT ;
102- let module = def_map. module_id ( local_id) ;
103- let resolver = module. resolver ( & db) ;
104132 let source = def_map[ local_id] . definition_source ( & db) ;
105133 let source_file = match source. value {
106134 ModuleSource :: SourceFile ( it) => it,
107135 ModuleSource :: Module ( _) | ModuleSource :: BlockExpr ( _) => panic ! ( ) ,
108136 } ;
109137
110- // What we want to do is to replace all macros (fn-like, derive, attr) with
111- // their expansions. Turns out, we don't actually store enough information
112- // to do this precisely though! Specifically, if a macro expands to nothing,
113- // it leaves zero traces in def-map, so we can't get its expansion after the
114- // fact.
115- //
116- // This is the usual
117- // <https://github.com/rust-lang/rust-analyzer/issues/3407>
118- // resolve/record tension!
119- //
120- // So here we try to do a resolve, which is necessary a heuristic. For macro
121- // calls, we use `as_call_id_with_errors`. For derives, we look at the impls
122- // in the module and assume that, if impls's source is a different
123- // `HirFileId`, than it came from macro expansion.
124-
125138 let mut text_edits = Vec :: new ( ) ;
126139 let mut expansions = Vec :: new ( ) ;
127140
128- for macro_call in source_file. syntax ( ) . descendants ( ) . filter_map ( ast:: MacroCall :: cast) {
129- let macro_call = InFile :: new ( source. file_id , & macro_call) ;
130- let res = macro_call
131- . as_call_id_with_errors (
132- & db,
133- krate,
134- |path| {
135- resolver
136- . resolve_path_as_macro ( & db, path, Some ( MacroSubNs :: Bang ) )
137- . map ( |( it, _) | db. macro_def ( it) )
138- } ,
139- & mut |_, _| ( ) ,
140- )
141- . unwrap ( ) ;
142- let macro_call_id = res. value . unwrap ( ) ;
143- let mut expansion_result = db. parse_macro_expansion ( macro_call_id) ;
144- expansion_result. err = expansion_result. err . or ( res. err ) ;
145- expansions. push ( ( macro_call. value . clone ( ) , expansion_result) ) ;
141+ for macro_call_node in source_file. syntax ( ) . descendants ( ) . filter_map ( ast:: MacroCall :: cast) {
142+ let ast_id = db. ast_id_map ( source. file_id ) . ast_id ( & macro_call_node) ;
143+ let ast_id = InFile :: new ( source. file_id , ast_id) ;
144+ let ptr = InFile :: new ( source. file_id , AstPtr :: new ( & macro_call_node) ) ;
145+ let macro_call_id = resolve ( & db, & def_map, ast_id, ptr)
146+ . unwrap_or_else ( || panic ! ( "unable to find semantic macro call {macro_call_node}" ) ) ;
147+ let expansion_result = db. parse_macro_expansion ( macro_call_id) ;
148+ expansions. push ( ( macro_call_node. clone ( ) , expansion_result) ) ;
146149 }
147150
148151 for ( call, exp) in expansions. into_iter ( ) . rev ( ) {
0 commit comments