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.rs85
1 files changed, 44 insertions, 41 deletions
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index 143b5df773..800c96ebda 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -19,7 +19,7 @@ use std::{iter, ops::Range, sync};
use base_db::RootQueryDb;
use expect_test::Expect;
use hir_expand::{
- InFile, MacroCallKind, MacroKind,
+ AstId, InFile, MacroCallId, MacroCallKind, MacroKind,
db::ExpandDatabase,
proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind},
span_map::SpanMapRef,
@@ -29,7 +29,7 @@ use itertools::Itertools;
use span::{Edition, Span};
use stdx::{format_to, format_to_acc};
use syntax::{
- AstNode,
+ AstNode, AstPtr,
SyntaxKind::{COMMENT, EOF, IDENT, LIFETIME_IDENT},
SyntaxNode, T,
ast::{self, edit::IndentLevel},
@@ -37,10 +37,9 @@ use syntax::{
use test_fixture::WithFixture;
use crate::{
- AdtId, AsMacroCall, Lookup, ModuleDefId,
+ AdtId, Lookup, ModuleDefId,
db::DefDatabase,
- nameres::{DefMap, MacroSubNs, ModuleSource},
- resolver::HasResolver,
+ nameres::{DefMap, ModuleSource},
src::HasSource,
test_db::TestDB,
tt::TopSubtree,
@@ -78,7 +77,6 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
expect.assert_eq(&errors);
}
-#[track_caller]
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) {
let extra_proc_macros = vec![(
r#"
@@ -95,54 +93,59 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
disabled: false,
},
)];
+
+ 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 = db.crate_def_map(krate);
let local_id = DefMap::ROOT;
- let module = def_map.module_id(local_id);
- let resolver = module.resolver(&db);
let source = def_map[local_id].definition_source(&db);
let source_file = match source.value {
ModuleSource::SourceFile(it) => it,
ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(),
};
- // What we want to do is to replace all macros (fn-like, derive, attr) with
- // their expansions. Turns out, we don't actually store enough information
- // to do this precisely though! Specifically, if a macro expands to nothing,
- // it leaves zero traces in def-map, so we can't get its expansion after the
- // fact.
- //
- // This is the usual
- // <https://github.com/rust-lang/rust-analyzer/issues/3407>
- // resolve/record tension!
- //
- // So here we try to do a resolve, which is necessary a heuristic. For macro
- // calls, we use `as_call_id_with_errors`. For derives, we look at the impls
- // in the module and assume that, if impls's source is a different
- // `HirFileId`, than it came from macro expansion.
-
let mut text_edits = Vec::new();
let mut expansions = Vec::new();
- for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
- let macro_call = InFile::new(source.file_id, &macro_call);
- let res = macro_call
- .as_call_id_with_errors(
- &db,
- krate,
- |path| {
- resolver
- .resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang))
- .map(|(it, _)| db.macro_def(it))
- },
- &mut |_, _| (),
- )
- .unwrap();
- let macro_call_id = res.value.unwrap();
- let mut expansion_result = db.parse_macro_expansion(macro_call_id);
- expansion_result.err = expansion_result.err.or(res.err);
- expansions.push((macro_call.value.clone(), expansion_result));
+ 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(&macro_call_node);
+ let ast_id = InFile::new(source.file_id, ast_id);
+ let ptr = InFile::new(source.file_id, AstPtr::new(&macro_call_node));
+ let macro_call_id = resolve(&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));
}
for (call, exp) in expansions.into_iter().rev() {