@@ -19,7 +19,7 @@ use std::{iter, ops::Range, sync};
19
19
use base_db:: RootQueryDb ;
20
20
use expect_test:: Expect ;
21
21
use hir_expand:: {
22
- InFile , MacroCallKind , MacroKind ,
22
+ AstId , InFile , MacroCallId , MacroCallKind , MacroKind ,
23
23
db:: ExpandDatabase ,
24
24
proc_macro:: { ProcMacro , ProcMacroExpander , ProcMacroExpansionError , ProcMacroKind } ,
25
25
span_map:: SpanMapRef ,
@@ -29,18 +29,17 @@ use itertools::Itertools;
29
29
use span:: { Edition , Span } ;
30
30
use stdx:: { format_to, format_to_acc} ;
31
31
use syntax:: {
32
- AstNode ,
32
+ AstNode , AstPtr ,
33
33
SyntaxKind :: { COMMENT , EOF , IDENT , LIFETIME_IDENT } ,
34
34
SyntaxNode , T ,
35
35
ast:: { self , edit:: IndentLevel } ,
36
36
} ;
37
37
use test_fixture:: WithFixture ;
38
38
39
39
use crate :: {
40
- AdtId , AsMacroCall , Lookup , ModuleDefId ,
40
+ AdtId , Lookup , ModuleDefId ,
41
41
db:: DefDatabase ,
42
- nameres:: { DefMap , MacroSubNs , ModuleSource } ,
43
- resolver:: HasResolver ,
42
+ nameres:: { DefMap , ModuleSource } ,
44
43
src:: HasSource ,
45
44
test_db:: TestDB ,
46
45
tt:: TopSubtree ,
@@ -78,7 +77,6 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
78
77
expect. assert_eq ( & errors) ;
79
78
}
80
79
81
- #[ track_caller]
82
80
fn check ( #[ rust_analyzer:: rust_fixture] ra_fixture : & str , mut expect : Expect ) {
83
81
let extra_proc_macros = vec ! [ (
84
82
r#"
@@ -95,54 +93,59 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
95
93
disabled: false ,
96
94
} ,
97
95
) ] ;
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
+
98
128
let db = TestDB :: with_files_extra_proc_macros ( ra_fixture, extra_proc_macros) ;
99
129
let krate = db. fetch_test_crate ( ) ;
100
130
let def_map = db. crate_def_map ( krate) ;
101
131
let local_id = DefMap :: ROOT ;
102
- let module = def_map. module_id ( local_id) ;
103
- let resolver = module. resolver ( & db) ;
104
132
let source = def_map[ local_id] . definition_source ( & db) ;
105
133
let source_file = match source. value {
106
134
ModuleSource :: SourceFile ( it) => it,
107
135
ModuleSource :: Module ( _) | ModuleSource :: BlockExpr ( _) => panic ! ( ) ,
108
136
} ;
109
137
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
-
125
138
let mut text_edits = Vec :: new ( ) ;
126
139
let mut expansions = Vec :: new ( ) ;
127
140
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) ) ;
146
149
}
147
150
148
151
for ( call, exp) in expansions. into_iter ( ) . rev ( ) {
0 commit comments