Unnamed repository; edit this file 'description' to name the repository.
Do not resolve proc macros in value ns (as functions), only in macro ns, outside their defining crate
The main impact is that syntax highlighting will show it as a macro and not a function.
| -rw-r--r-- | crates/hir-def/src/item_scope.rs | 5 | ||||
| -rw-r--r-- | crates/hir-def/src/nameres.rs | 8 | ||||
| -rw-r--r-- | crates/hir-def/src/nameres/collector.rs | 12 | ||||
| -rw-r--r-- | crates/hir-def/src/nameres/tests/macros.rs | 6 | ||||
| -rw-r--r-- | crates/hir-def/src/resolver.rs | 11 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/simple.rs | 35 | ||||
| -rw-r--r-- | crates/ide/src/references.rs | 2 | ||||
| -rw-r--r-- | crates/ide/src/syntax_highlighting/test_data/highlight_macros.html | 3 | ||||
| -rw-r--r-- | crates/ide/src/syntax_highlighting/tests.rs | 8 |
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, |