aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-09-18 16:50:04 +0100
committerJonas Schievink <[email protected]>2020-09-18 16:50:04 +0100
commitbaab72e611fa985c2e62e964f3a48ad31367220f (patch)
tree278514b9e672529c43f20410fce7ce49b3d0ba89 /crates/hir_def
parent069045015c4b400754632c505f6ef19e32f9a4db (diff)
Reduce visibility of non-proc-macros
proc-macro crates only export proc-macros, but currently other items are also considered public (and show up in completion)
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/item_scope.rs25
-rw-r--r--crates/hir_def/src/nameres/collector.rs19
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs41
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
6use base_db::CrateId; 6use base_db::CrateId;
7use hir_expand::name::Name; 7use hir_expand::name::Name;
8use hir_expand::MacroDefKind;
8use once_cell::sync::Lazy; 9use once_cell::sync::Lazy;
9use rustc_hash::{FxHashMap, FxHashSet}; 10use rustc_hash::{FxHashMap, FxHashSet};
10use test_utils::mark; 11use test_utils::mark;
11 12
13use crate::ModuleId;
12use crate::{ 14use 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
270impl PerNs { 295impl 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]
704fn 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}