@@ -19,15 +19,18 @@ use std::{any::TypeId, iter, ops::Range, sync};
1919use base_db:: RootQueryDb ;
2020use expect_test:: Expect ;
2121use hir_expand:: {
22- AstId , InFile , MacroCallId , MacroCallKind , MacroKind ,
22+ AstId , ExpansionInfo , InFile , MacroCallId , MacroCallKind , MacroKind ,
2323 builtin:: quote:: quote,
2424 db:: ExpandDatabase ,
2525 proc_macro:: { ProcMacro , ProcMacroExpander , ProcMacroExpansionError , ProcMacroKind } ,
2626 span_map:: SpanMapRef ,
2727} ;
2828use intern:: { Symbol , sym} ;
2929use itertools:: Itertools ;
30- use span:: { Edition , ROOT_ERASED_FILE_AST_ID , Span , SpanAnchor , SyntaxContext } ;
30+ use span:: {
31+ Edition , NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER , ROOT_ERASED_FILE_AST_ID , Span , SpanAnchor ,
32+ SyntaxContext ,
33+ } ;
3134use stdx:: { format_to, format_to_acc} ;
3235use syntax:: {
3336 AstNode , AstPtr ,
@@ -97,37 +100,6 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
97100 } ,
98101 ) ] ;
99102
100- fn resolve (
101- db : & dyn DefDatabase ,
102- def_map : & DefMap ,
103- ast_id : AstId < ast:: MacroCall > ,
104- ast_ptr : InFile < AstPtr < ast:: MacroCall > > ,
105- ) -> Option < MacroCallId > {
106- def_map. modules ( ) . find_map ( |module| {
107- for decl in
108- module. 1 . scope . declarations ( ) . chain ( module. 1 . scope . unnamed_consts ( ) . map ( Into :: into) )
109- {
110- let body = match decl {
111- ModuleDefId :: FunctionId ( it) => it. into ( ) ,
112- ModuleDefId :: ConstId ( it) => it. into ( ) ,
113- ModuleDefId :: StaticId ( it) => it. into ( ) ,
114- _ => continue ,
115- } ;
116-
117- let ( body, sm) = db. body_with_source_map ( body) ;
118- if let Some ( it) =
119- body. blocks ( db) . find_map ( |block| resolve ( db, block. 1 , ast_id, ast_ptr) )
120- {
121- return Some ( it) ;
122- }
123- if let Some ( ( _, res) ) = sm. macro_calls ( ) . find ( |it| it. 0 == ast_ptr) {
124- return Some ( res) ;
125- }
126- }
127- module. 1 . scope . macro_invoc ( ast_id)
128- } )
129- }
130-
131103 let db = TestDB :: with_files_extra_proc_macros ( ra_fixture, extra_proc_macros) ;
132104 let krate = db. fetch_test_crate ( ) ;
133105 let def_map = crate_def_map ( & db, krate) ;
@@ -144,7 +116,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
144116 let ast_id = db. ast_id_map ( source. file_id ) . ast_id ( & macro_call_node) ;
145117 let ast_id = InFile :: new ( source. file_id , ast_id) ;
146118 let ptr = InFile :: new ( source. file_id , AstPtr :: new ( & macro_call_node) ) ;
147- let macro_call_id = resolve ( & db, def_map, ast_id, ptr)
119+ let macro_call_id = resolve_macro_call_id ( & db, def_map, ast_id, ptr)
148120 . unwrap_or_else ( || panic ! ( "unable to find semantic macro call {macro_call_node}" ) ) ;
149121 let expansion_result = db. parse_macro_expansion ( macro_call_id) ;
150122 expansions. push ( ( macro_call_node. clone ( ) , expansion_result) ) ;
@@ -278,6 +250,38 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
278250 expect. assert_eq ( & expanded_text) ;
279251}
280252
253+ fn resolve_macro_call_id (
254+ db : & dyn DefDatabase ,
255+ def_map : & DefMap ,
256+ ast_id : AstId < ast:: MacroCall > ,
257+ ast_ptr : InFile < AstPtr < ast:: MacroCall > > ,
258+ ) -> Option < MacroCallId > {
259+ def_map. modules ( ) . find_map ( |module| {
260+ for decl in
261+ module. 1 . scope . declarations ( ) . chain ( module. 1 . scope . unnamed_consts ( ) . map ( Into :: into) )
262+ {
263+ let body = match decl {
264+ ModuleDefId :: FunctionId ( it) => it. into ( ) ,
265+ ModuleDefId :: ConstId ( it) => it. into ( ) ,
266+ ModuleDefId :: StaticId ( it) => it. into ( ) ,
267+ _ => continue ,
268+ } ;
269+
270+ let ( body, sm) = db. body_with_source_map ( body) ;
271+ if let Some ( it) = body
272+ . blocks ( db)
273+ . find_map ( |block| resolve_macro_call_id ( db, block. 1 , ast_id, ast_ptr) )
274+ {
275+ return Some ( it) ;
276+ }
277+ if let Some ( ( _, res) ) = sm. macro_calls ( ) . find ( |it| it. 0 == ast_ptr) {
278+ return Some ( res) ;
279+ }
280+ }
281+ module. 1 . scope . macro_invoc ( ast_id)
282+ } )
283+ }
284+
281285fn reindent ( indent : IndentLevel , pp : String ) -> String {
282286 if !pp. contains ( '\n' ) {
283287 return pp;
@@ -430,3 +434,47 @@ fn regression_20171() {
430434 Edition :: CURRENT
431435 } ) ;
432436}
437+
438+ #[ test]
439+ fn no_downmap ( ) {
440+ let fixture = r#"
441+ macro_rules! m {
442+ ($func_name:ident) => {
443+ fn $func_name() { todo!() }
444+ };
445+ }
446+ m!(f);
447+ m!(g);
448+ "# ;
449+
450+ let ( db, file_id) = TestDB :: with_single_file ( fixture) ;
451+ let krate = file_id. krate ( & db) ;
452+ let def_map = crate_def_map ( & db, krate) ;
453+ let source = def_map[ def_map. root ] . definition_source ( & db) ;
454+ let source_file = match source. value {
455+ ModuleSource :: SourceFile ( it) => it,
456+ ModuleSource :: Module ( _) | ModuleSource :: BlockExpr ( _) => panic ! ( ) ,
457+ } ;
458+ let no_downmap_spans: Vec < _ > = source_file
459+ . syntax ( )
460+ . descendants ( )
461+ . map ( |node| {
462+ let mut span = db. real_span_map ( file_id) . span_for_range ( node. text_range ( ) ) ;
463+ span. anchor . ast_id = NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER ;
464+ span
465+ } )
466+ . collect ( ) ;
467+
468+ for macro_call_node in source_file. syntax ( ) . descendants ( ) . filter_map ( ast:: MacroCall :: cast) {
469+ let ast_id = db. ast_id_map ( source. file_id ) . ast_id ( & macro_call_node) ;
470+ let ast_id = InFile :: new ( source. file_id , ast_id) ;
471+ let ptr = InFile :: new ( source. file_id , AstPtr :: new ( & macro_call_node) ) ;
472+ let macro_call_id = resolve_macro_call_id ( & db, def_map, ast_id, ptr)
473+ . unwrap_or_else ( || panic ! ( "unable to find semantic macro call {macro_call_node}" ) ) ;
474+ let expansion_info = ExpansionInfo :: new ( & db, macro_call_id) ;
475+ for & span in no_downmap_spans. iter ( ) {
476+ assert ! ( expansion_info. map_range_down( span) . is_none( ) ) ;
477+ assert ! ( expansion_info. map_range_down_exact( span) . is_none( ) ) ;
478+ }
479+ }
480+ }
0 commit comments