Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/macro_expansion_tests/mod.rs')
| -rw-r--r-- | crates/hir-def/src/macro_expansion_tests/mod.rs | 160 |
1 files changed, 114 insertions, 46 deletions
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index e8ae499d27..3f136bc591 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -16,10 +16,10 @@ mod proc_macros; use std::{any::TypeId, iter, ops::Range, sync}; -use base_db::RootQueryDb; +use base_db::{RootQueryDb, SourceDatabase}; use expect_test::Expect; use hir_expand::{ - AstId, InFile, MacroCallId, MacroCallKind, MacroKind, + AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind, builtin::quote::quote, db::ExpandDatabase, proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind}, @@ -27,7 +27,10 @@ use hir_expand::{ }; use intern::{Symbol, sym}; use itertools::Itertools; -use span::{Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext}; +use span::{ + Edition, NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, + SyntaxContext, +}; use stdx::{format_to, format_to_acc}; use syntax::{ AstNode, AstPtr, @@ -50,6 +53,8 @@ use crate::{ #[track_caller] fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false); + let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); let def_map = crate_def_map(&db, krate); @@ -77,10 +82,15 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) .sorted_unstable_by_key(|(range, _)| range.start()) .format_with("\n", |(range, err), format| format(&format_args!("{range:?}: {err}"))) .to_string(); + + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true); + expect.assert_eq(&errors); } fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) { + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false); + let extra_proc_macros = vec![( r#" #[proc_macro_attribute] @@ -97,42 +107,10 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream }, )]; - fn resolve( - db: &dyn DefDatabase, - def_map: &DefMap, - ast_id: AstId<ast::MacroCall>, - ast_ptr: InFile<AstPtr<ast::MacroCall>>, - ) -> Option<MacroCallId> { - def_map.modules().find_map(|module| { - for decl in - module.1.scope.declarations().chain(module.1.scope.unnamed_consts().map(Into::into)) - { - let body = match decl { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => continue, - }; - - let (body, sm) = db.body_with_source_map(body); - if let Some(it) = - body.blocks(db).find_map(|block| resolve(db, block.1, ast_id, ast_ptr)) - { - return Some(it); - } - if let Some((_, res)) = sm.macro_calls().find(|it| it.0 == ast_ptr) { - return Some(res); - } - } - module.1.scope.macro_invoc(ast_id) - }) - } - let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); let krate = db.fetch_test_crate(); let def_map = crate_def_map(&db, krate); - let local_id = DefMap::ROOT; - let source = def_map[local_id].definition_source(&db); + let source = def_map[def_map.root].definition_source(&db); let source_file = match source.value { ModuleSource::SourceFile(it) => it, ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(), @@ -145,7 +123,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node); let ast_id = InFile::new(source.file_id, ast_id); let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node)); - let macro_call_id = resolve(&db, def_map, ast_id, ptr) + let macro_call_id = resolve_macro_call_id(&db, def_map, ast_id, ptr) .unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}")); let expansion_result = db.parse_macro_expansion(macro_call_id); expansions.push((macro_call_node.clone(), expansion_result)); @@ -209,7 +187,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream expanded_text.replace_range(range, &text); } - for decl_id in def_map[local_id].scope.declarations() { + for decl_id in def_map[def_map.root].scope.declarations() { // FIXME: I'm sure there's already better way to do this let src = match decl_id { ModuleDefId::AdtId(AdtId::StructId(struct_id)) => { @@ -245,7 +223,22 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream } } - for impl_id in def_map[local_id].scope.impls() { + for (_, module) in def_map.modules() { + let Some(src) = module.declaration_source(&db) else { + continue; + }; + if let Some(macro_file) = src.file_id.macro_file() { + let pp = pretty_print_macro_expansion( + src.value.syntax().clone(), + db.span_map(macro_file.into()).as_ref(), + false, + false, + ); + format_to!(expanded_text, "\n{}", pp) + } + } + + for impl_id in def_map[def_map.root].scope.impls() { let src = impl_id.lookup(&db).source(&db); if let Some(macro_file) = src.file_id.macro_file() && let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db) @@ -260,10 +253,44 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream } } + crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true); + expect.indent(false); expect.assert_eq(&expanded_text); } +fn resolve_macro_call_id( + db: &dyn DefDatabase, + def_map: &DefMap, + ast_id: AstId<ast::MacroCall>, + ast_ptr: InFile<AstPtr<ast::MacroCall>>, +) -> Option<MacroCallId> { + def_map.modules().find_map(|module| { + for decl in + module.1.scope.declarations().chain(module.1.scope.unnamed_consts().map(Into::into)) + { + let body = match decl { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => continue, + }; + + let (body, sm) = db.body_with_source_map(body); + if let Some(it) = body + .blocks(db) + .find_map(|block| resolve_macro_call_id(db, block.1, ast_id, ast_ptr)) + { + return Some(it); + } + if let Some((_, res)) = sm.macro_calls().find(|it| it.0 == ast_ptr) { + return Some(res); + } + } + module.1.scope.macro_invoc(ast_id) + }) +} + fn reindent(indent: IndentLevel, pp: String) -> String { if !pp.contains('\n') { return pp; @@ -360,6 +387,7 @@ struct IdentityWhenValidProcMacroExpander; impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &base_db::Env, @@ -372,7 +400,6 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { subtree, syntax_bridge::TopEntryPoint::MacroItems, &mut |_| span::Edition::CURRENT, - span::Edition::CURRENT, ); if parse.errors().is_empty() { Ok(subtree.clone()) @@ -413,10 +440,51 @@ fn regression_20171() { #dollar_crate::panic::panic_2021!(); }} }; - token_tree_to_syntax_node( - &tt, - syntax_bridge::TopEntryPoint::MacroStmts, - &mut |_| Edition::CURRENT, - Edition::CURRENT, - ); + token_tree_to_syntax_node(&tt, syntax_bridge::TopEntryPoint::MacroStmts, &mut |_| { + Edition::CURRENT + }); +} + +#[test] +fn no_downmap() { + let fixture = r#" +macro_rules! m { + ($func_name:ident) => { + fn $func_name() { todo!() } + }; +} +m!(f); +m!(g); + "#; + + let (db, file_id) = TestDB::with_single_file(fixture); + let krate = file_id.krate(&db); + let def_map = crate_def_map(&db, krate); + let source = def_map[def_map.root].definition_source(&db); + let source_file = match source.value { + ModuleSource::SourceFile(it) => it, + ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(), + }; + let no_downmap_spans: Vec<_> = source_file + .syntax() + .descendants() + .map(|node| { + let mut span = db.real_span_map(file_id).span_for_range(node.text_range()); + span.anchor.ast_id = NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER; + span + }) + .collect(); + + for macro_call_node in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { + let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node); + let ast_id = InFile::new(source.file_id, ast_id); + let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node)); + let macro_call_id = resolve_macro_call_id(&db, def_map, ast_id, ptr) + .unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}")); + let expansion_info = ExpansionInfo::new(&db, macro_call_id); + for &span in no_downmap_spans.iter() { + assert!(expansion_info.map_range_down(span).is_none()); + assert!(expansion_info.map_range_down_exact(span).is_none()); + } + } } |