Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/item_scope.rs5
-rw-r--r--crates/hir-def/src/nameres.rs8
-rw-r--r--crates/hir-def/src/nameres/collector.rs12
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs6
-rw-r--r--crates/hir-def/src/resolver.rs11
-rw-r--r--crates/hir-ty/src/tests/simple.rs35
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_macros.html3
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs8
9 files changed, 79 insertions, 11 deletions
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 1303773b59..b11a8bcd90 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -483,6 +483,11 @@ impl ItemScope {
self.declarations.push(def)
}
+ pub(crate) fn remove_from_value_ns(&mut self, name: &Name, def: ModuleDefId) {
+ let entry = self.values.shift_remove(name);
+ assert!(entry.is_some_and(|entry| entry.def == def))
+ }
+
pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
self.legacy_macros.get(name).map(|it| &**it)
}
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 1e3ea50c5a..5fda1beab4 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -211,6 +211,7 @@ struct DefMapCrateData {
/// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroId, Box<[Name]>>,
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
+ fn_proc_macro_mapping_back: FxHashMap<ProcMacroId, FunctionId>,
/// Custom tool modules registered with `#![register_tool]`.
registered_tools: Vec<Symbol>,
@@ -230,6 +231,7 @@ impl DefMapCrateData {
Self {
exported_derives: FxHashMap::default(),
fn_proc_macro_mapping: FxHashMap::default(),
+ fn_proc_macro_mapping_back: FxHashMap::default(),
registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(),
unstable_features: FxHashSet::default(),
rustc_coherence_is_core: false,
@@ -244,6 +246,7 @@ impl DefMapCrateData {
let Self {
exported_derives,
fn_proc_macro_mapping,
+ fn_proc_macro_mapping_back,
registered_tools,
unstable_features,
rustc_coherence_is_core: _,
@@ -254,6 +257,7 @@ impl DefMapCrateData {
} = self;
exported_derives.shrink_to_fit();
fn_proc_macro_mapping.shrink_to_fit();
+ fn_proc_macro_mapping_back.shrink_to_fit();
registered_tools.shrink_to_fit();
unstable_features.shrink_to_fit();
}
@@ -570,6 +574,10 @@ impl DefMap {
self.data.fn_proc_macro_mapping.get(&id).copied()
}
+ pub fn proc_macro_as_fn(&self, id: ProcMacroId) -> Option<FunctionId> {
+ self.data.fn_proc_macro_mapping_back.get(&id).copied()
+ }
+
pub fn krate(&self) -> Crate {
self.krate
}
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index f51524c1b5..e672e83f01 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -634,6 +634,7 @@ impl<'db> DefCollector<'db> {
crate_data.exported_derives.insert(proc_macro_id.into(), helpers);
}
crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
+ crate_data.fn_proc_macro_mapping_back.insert(proc_macro_id, fn_id);
}
/// Define a macro with `macro_rules`.
@@ -2095,6 +2096,8 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
+ update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
+
if self.def_collector.def_map.block.is_none()
&& self.def_collector.is_proc_macro
&& self.module_id == self.def_collector.def_map.root
@@ -2105,9 +2108,14 @@ impl ModCollector<'_, '_> {
InFile::new(self.file_id(), id),
fn_id,
);
- }
- update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
+ // A proc macro is implemented as a function, but it's treated as a macro, not a function.
+ // You cannot call it like a function, for example, except in its defining crate.
+ // So we keep the function definition, but remove it from the scope, leaving only the macro.
+ self.def_collector.def_map[module_id]
+ .scope
+ .remove_from_value_ns(&it.name, fn_id.into());
+ }
}
ModItemId::Struct(id) => {
let it = &self.item_tree[id];
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index a943f6f0ac..a013f8b2bc 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -1068,10 +1068,8 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
- AnotherTrait : macro#
- DummyTrait : macro#
- TokenStream : type value
- - attribute_macro : value macro#
- - derive_macro : value
- - derive_macro_2 : value
- - function_like_macro : value macro!
+ - attribute_macro : macro#
+ - function_like_macro : macro!
"#]],
);
}
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 2ac0f90fb2..c10a0ac3eb 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -1153,7 +1153,7 @@ impl<'db> ModuleItemMap<'db> {
);
match unresolved_idx {
None => {
- let (value, import) = to_value_ns(module_def)?;
+ let (value, import) = to_value_ns(module_def, self.def_map)?;
Some((ResolveValueResult::ValueNs(value, import), prefix_info))
}
Some(unresolved_idx) => {
@@ -1194,8 +1194,13 @@ impl<'db> ModuleItemMap<'db> {
}
}
-fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
- let (def, import) = per_ns.take_values_import()?;
+fn to_value_ns(per_ns: PerNs, def_map: &DefMap) -> Option<(ValueNs, Option<ImportOrGlob>)> {
+ let (def, import) = per_ns.take_values_import().or_else(|| {
+ let Some(MacroId::ProcMacroId(proc_macro)) = per_ns.take_macros() else { return None };
+ // If we cannot resolve to value ns, but we can resolve to a proc macro, and this is the crate
+ // defining this proc macro - inside this crate, we should treat the macro as a function.
+ def_map.proc_macro_as_fn(proc_macro).map(|it| (ModuleDefId::FunctionId(it), None))
+ })?;
let res = match def {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 7d4f04268a..dab8bdb54b 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -4074,3 +4074,38 @@ static S: &[u8; 158] = include_bytes!("/foo/bar/baz.txt");
"#,
);
}
+
+#[test]
+fn proc_macros_are_functions_inside_defining_crate_and_macros_outside() {
+ check_types(
+ r#"
+//- /pm.rs crate:pm
+#![crate_type = "proc-macro"]
+
+#[proc_macro_attribute]
+pub fn proc_macro() {}
+
+fn foo() {
+ proc_macro;
+ // ^^^^^^^^^^ fn proc_macro()
+}
+
+mod bar {
+ use super::proc_macro;
+
+ fn baz() {
+ super::proc_macro;
+ // ^^^^^^^^^^^^^^^^^ fn proc_macro()
+ proc_macro;
+ // ^^^^^^^^^^ fn proc_macro()
+ }
+}
+
+//- /lib.rs crate:lib deps:pm
+fn foo() {
+ pm::proc_macro;
+ // ^^^^^^^^^^^^^^ {unknown}
+}
+ "#,
+ );
+}
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 5443021988..38ee097033 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -2073,6 +2073,7 @@ fn func() {}
expect![[r#"
identity Attribute FileId(1) 1..107 32..40
+ FileId(0) 17..25 import
FileId(0) 43..51
"#]],
);
@@ -2103,6 +2104,7 @@ mirror$0! {}
expect![[r#"
mirror ProcMacro FileId(1) 1..77 22..28
+ FileId(0) 17..23 import
FileId(0) 26..32
"#]],
)
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index 59612634fd..740a6272a7 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -41,7 +41,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
</style>
-<pre><code><span class="keyword">use</span> <span class="crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="function library">mirror</span><span class="comma">,</span> <span class="function library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
+<pre><code><span class="keyword">use</span> <span class="crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="proc_macro library">mirror</span><span class="comma">,</span> <span class="attribute library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
+<span class="keyword">use</span> <span class="crate_root library">pm</span><span class="operator">::</span><span class="attribute library">proc_macro</span><span class="semicolon">;</span>
<span class="proc_macro library">mirror</span><span class="macro_bang">!</span> <span class="brace">{</span>
<span class="brace macro proc_macro">{</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 8b529cf10f..c6aebd0b0c 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -55,8 +55,9 @@ fn macros() {
r#"
//- proc_macros: mirror, identity, derive_identity
//- minicore: fmt, include, concat
-//- /lib.rs crate:lib
+//- /lib.rs crate:lib deps:pm
use proc_macros::{mirror, identity, DeriveIdentity};
+use pm::proc_macro;
mirror! {
{
@@ -126,6 +127,11 @@ fn main() {
//- /foo/foo.rs crate:foo
mod foo {}
use self::foo as bar;
+//- /pm.rs crate:pm
+#![crate_type = "proc-macro"]
+
+#[proc_macro_attribute]
+pub fn proc_macro() {}
"#,
expect_file!["./test_data/highlight_macros.html"],
false,