Unnamed repository; edit this file 'description' to name the repository.
| -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, |