diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_def/src/item_scope.rs | 25 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 19 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 41 |
3 files changed, 85 insertions, 0 deletions
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index f1e9dfd5b..99820c275 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -5,10 +5,12 @@ use std::collections::hash_map::Entry; | |||
5 | 5 | ||
6 | use base_db::CrateId; | 6 | use base_db::CrateId; |
7 | use hir_expand::name::Name; | 7 | use hir_expand::name::Name; |
8 | use hir_expand::MacroDefKind; | ||
8 | use once_cell::sync::Lazy; | 9 | use once_cell::sync::Lazy; |
9 | use rustc_hash::{FxHashMap, FxHashSet}; | 10 | use rustc_hash::{FxHashMap, FxHashSet}; |
10 | use test_utils::mark; | 11 | use test_utils::mark; |
11 | 12 | ||
13 | use crate::ModuleId; | ||
12 | use crate::{ | 14 | use crate::{ |
13 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 15 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
14 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId, | 16 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId, |
@@ -265,6 +267,29 @@ impl ItemScope { | |||
265 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | 267 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { |
266 | self.legacy_macros.clone() | 268 | self.legacy_macros.clone() |
267 | } | 269 | } |
270 | |||
271 | /// Marks everything that is not a procedural macro as private to `this_module`. | ||
272 | pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { | ||
273 | for vis in self | ||
274 | .types | ||
275 | .values_mut() | ||
276 | .chain(self.values.values_mut()) | ||
277 | .map(|(_, v)| v) | ||
278 | .chain(self.unnamed_trait_imports.values_mut()) | ||
279 | { | ||
280 | *vis = Visibility::Module(this_module); | ||
281 | } | ||
282 | |||
283 | for (mac, vis) in self.macros.values_mut() { | ||
284 | if let MacroDefKind::ProcMacro(_) = mac.kind { | ||
285 | // FIXME: Technically this is insufficient since reexports of proc macros are also | ||
286 | // forbidden. Practically nobody does that. | ||
287 | continue; | ||
288 | } | ||
289 | |||
290 | *vis = Visibility::Module(this_module); | ||
291 | } | ||
292 | } | ||
268 | } | 293 | } |
269 | 294 | ||
270 | impl PerNs { | 295 | impl PerNs { |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 28ef49488..f98a42643 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -87,6 +87,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr | |||
87 | mod_dirs: FxHashMap::default(), | 87 | mod_dirs: FxHashMap::default(), |
88 | cfg_options, | 88 | cfg_options, |
89 | proc_macros, | 89 | proc_macros, |
90 | exports_proc_macros: false, | ||
90 | from_glob_import: Default::default(), | 91 | from_glob_import: Default::default(), |
91 | }; | 92 | }; |
92 | collector.collect(); | 93 | collector.collect(); |
@@ -203,6 +204,7 @@ struct DefCollector<'a> { | |||
203 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 204 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
204 | cfg_options: &'a CfgOptions, | 205 | cfg_options: &'a CfgOptions, |
205 | proc_macros: Vec<(Name, ProcMacroExpander)>, | 206 | proc_macros: Vec<(Name, ProcMacroExpander)>, |
207 | exports_proc_macros: bool, | ||
206 | from_glob_import: PerNsGlobImports, | 208 | from_glob_import: PerNsGlobImports, |
207 | } | 209 | } |
208 | 210 | ||
@@ -260,9 +262,25 @@ impl DefCollector<'_> { | |||
260 | self.record_resolved_import(directive) | 262 | self.record_resolved_import(directive) |
261 | } | 263 | } |
262 | self.unresolved_imports = unresolved_imports; | 264 | self.unresolved_imports = unresolved_imports; |
265 | |||
266 | // FIXME: This condition should instead check if this is a `proc-macro` type crate. | ||
267 | if self.exports_proc_macros { | ||
268 | // A crate exporting procedural macros is not allowed to export anything else. | ||
269 | // | ||
270 | // Additionally, while the proc macro entry points must be `pub`, they are not publicly | ||
271 | // exported in type/value namespace. This function reduces the visibility of all items | ||
272 | // in the crate root that aren't proc macros. | ||
273 | let root = self.def_map.root; | ||
274 | let root = &mut self.def_map.modules[root]; | ||
275 | root.scope.censor_non_proc_macros(ModuleId { | ||
276 | krate: self.def_map.krate, | ||
277 | local_id: self.def_map.root, | ||
278 | }); | ||
279 | } | ||
263 | } | 280 | } |
264 | 281 | ||
265 | fn resolve_proc_macro(&mut self, name: &Name) { | 282 | fn resolve_proc_macro(&mut self, name: &Name) { |
283 | self.exports_proc_macros = true; | ||
266 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { | 284 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { |
267 | Some((_, expander)) => MacroDefId { | 285 | Some((_, expander)) => MacroDefId { |
268 | ast_id: None, | 286 | ast_id: None, |
@@ -1310,6 +1328,7 @@ mod tests { | |||
1310 | mod_dirs: FxHashMap::default(), | 1328 | mod_dirs: FxHashMap::default(), |
1311 | cfg_options: &CfgOptions::default(), | 1329 | cfg_options: &CfgOptions::default(), |
1312 | proc_macros: Default::default(), | 1330 | proc_macros: Default::default(), |
1331 | exports_proc_macros: false, | ||
1313 | from_glob_import: Default::default(), | 1332 | from_glob_import: Default::default(), |
1314 | }; | 1333 | }; |
1315 | collector.collect(); | 1334 | collector.collect(); |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 98cb5a0fd..0851c3b7d 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -699,3 +699,44 @@ fn resolves_proc_macros() { | |||
699 | "#]], | 699 | "#]], |
700 | ); | 700 | ); |
701 | } | 701 | } |
702 | |||
703 | #[test] | ||
704 | fn proc_macro_censoring() { | ||
705 | // Make sure that only proc macros are publicly exported from proc-macro crates. | ||
706 | |||
707 | check( | ||
708 | r" | ||
709 | //- /main.rs crate:main deps:macros | ||
710 | pub use macros::*; | ||
711 | |||
712 | //- /macros.rs crate:macros | ||
713 | pub struct TokenStream; | ||
714 | |||
715 | #[proc_macro] | ||
716 | pub fn function_like_macro(args: TokenStream) -> TokenStream { | ||
717 | args | ||
718 | } | ||
719 | |||
720 | #[proc_macro_attribute] | ||
721 | pub fn attribute_macro(_args: TokenStream, item: TokenStream) -> TokenStream { | ||
722 | item | ||
723 | } | ||
724 | |||
725 | #[proc_macro_derive(DummyTrait)] | ||
726 | pub fn derive_macro(_item: TokenStream) -> TokenStream { | ||
727 | TokenStream | ||
728 | } | ||
729 | |||
730 | #[macro_export] | ||
731 | macro_rules! mbe { | ||
732 | () => {}; | ||
733 | } | ||
734 | ", | ||
735 | expect![[r#" | ||
736 | crate | ||
737 | DummyTrait: m | ||
738 | attribute_macro: m | ||
739 | function_like_macro: m | ||
740 | "#]], | ||
741 | ); | ||
742 | } | ||