mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Add macro_use
prelude to DefMap
This commit is contained in:
parent
96113b7b8e
commit
3203ea896d
4 changed files with 84 additions and 20 deletions
|
@ -105,6 +105,9 @@ pub struct DefMap {
|
||||||
prelude: Option<ModuleId>,
|
prelude: Option<ModuleId>,
|
||||||
/// The extern prelude is only populated for non-block DefMaps
|
/// The extern prelude is only populated for non-block DefMaps
|
||||||
extern_prelude: FxHashMap<Name, ModuleId>,
|
extern_prelude: FxHashMap<Name, ModuleId>,
|
||||||
|
/// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that
|
||||||
|
/// this contains all kinds of macro, not just `macro_rules!` macro.
|
||||||
|
macro_use_prelude: FxHashMap<Name, MacroId>,
|
||||||
|
|
||||||
/// Side table for resolving derive helpers.
|
/// Side table for resolving derive helpers.
|
||||||
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
|
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
|
||||||
|
@ -277,6 +280,7 @@ impl DefMap {
|
||||||
edition,
|
edition,
|
||||||
recursion_limit: None,
|
recursion_limit: None,
|
||||||
extern_prelude: FxHashMap::default(),
|
extern_prelude: FxHashMap::default(),
|
||||||
|
macro_use_prelude: FxHashMap::default(),
|
||||||
exported_derives: FxHashMap::default(),
|
exported_derives: FxHashMap::default(),
|
||||||
fn_proc_macro_mapping: FxHashMap::default(),
|
fn_proc_macro_mapping: FxHashMap::default(),
|
||||||
proc_macro_loading_error: None,
|
proc_macro_loading_error: None,
|
||||||
|
@ -489,6 +493,7 @@ impl DefMap {
|
||||||
_c: _,
|
_c: _,
|
||||||
exported_derives,
|
exported_derives,
|
||||||
extern_prelude,
|
extern_prelude,
|
||||||
|
macro_use_prelude,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
modules,
|
modules,
|
||||||
registered_attrs,
|
registered_attrs,
|
||||||
|
@ -507,6 +512,7 @@ impl DefMap {
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
extern_prelude.shrink_to_fit();
|
extern_prelude.shrink_to_fit();
|
||||||
|
macro_use_prelude.shrink_to_fit();
|
||||||
exported_derives.shrink_to_fit();
|
exported_derives.shrink_to_fit();
|
||||||
diagnostics.shrink_to_fit();
|
diagnostics.shrink_to_fit();
|
||||||
modules.shrink_to_fit();
|
modules.shrink_to_fit();
|
||||||
|
|
|
@ -707,6 +707,7 @@ impl DefCollector<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import macros from `#[macro_use] extern crate`.
|
/// Import macros from `#[macro_use] extern crate`.
|
||||||
|
// FIXME: Support `#[macro_rules(macro_name, ...)]`.
|
||||||
fn import_macros_from_extern_crate(
|
fn import_macros_from_extern_crate(
|
||||||
&mut self,
|
&mut self,
|
||||||
current_module_id: LocalModuleId,
|
current_module_id: LocalModuleId,
|
||||||
|
@ -725,7 +726,7 @@ impl DefCollector<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
|
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
|
||||||
self.import_all_macros_exported(current_module_id, m.krate);
|
self.import_all_macros_exported(m.krate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,11 +735,12 @@ impl DefCollector<'_> {
|
||||||
/// Exported macros are just all macros in the root module scope.
|
/// Exported macros are just all macros in the root module scope.
|
||||||
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
|
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
|
||||||
/// created by `use` in the root module, ignoring the visibility of `use`.
|
/// created by `use` in the root module, ignoring the visibility of `use`.
|
||||||
fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
|
fn import_all_macros_exported(&mut self, krate: CrateId) {
|
||||||
let def_map = self.db.crate_def_map(krate);
|
let def_map = self.db.crate_def_map(krate);
|
||||||
for (name, def) in def_map[def_map.root].scope.macros() {
|
for (name, def) in def_map[def_map.root].scope.macros() {
|
||||||
// `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
|
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
|
||||||
self.define_legacy_macro(current_module_id, name.clone(), def);
|
// macros.
|
||||||
|
self.def_map.macro_use_prelude.insert(name.clone(), def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1509,6 +1511,7 @@ impl ModCollector<'_, '_> {
|
||||||
|
|
||||||
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
|
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
|
||||||
let krate = self.def_collector.def_map.krate;
|
let krate = self.def_collector.def_map.krate;
|
||||||
|
let is_crate_root = self.module_id == self.def_collector.def_map.root;
|
||||||
|
|
||||||
// Note: don't assert that inserted value is fresh: it's simply not true
|
// Note: don't assert that inserted value is fresh: it's simply not true
|
||||||
// for macros.
|
// for macros.
|
||||||
|
@ -1516,19 +1519,24 @@ impl ModCollector<'_, '_> {
|
||||||
|
|
||||||
// Prelude module is always considered to be `#[macro_use]`.
|
// Prelude module is always considered to be `#[macro_use]`.
|
||||||
if let Some(prelude_module) = self.def_collector.def_map.prelude {
|
if let Some(prelude_module) = self.def_collector.def_map.prelude {
|
||||||
if prelude_module.krate != krate {
|
if prelude_module.krate != krate && is_crate_root {
|
||||||
cov_mark::hit!(prelude_is_macro_use);
|
cov_mark::hit!(prelude_is_macro_use);
|
||||||
self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
|
self.def_collector.import_all_macros_exported(prelude_module.krate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should be processed eagerly instead of deferred to resolving.
|
// This should be processed eagerly instead of deferred to resolving.
|
||||||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||||
// any other items.
|
// any other items.
|
||||||
for &item in items {
|
//
|
||||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
// If we're not at the crate root, `macro_use`d extern crates are an error so let's just
|
||||||
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
// ignore them.
|
||||||
if let ModItem::ExternCrate(id) = item {
|
// FIXME: Support `#[macro_rules(macro_name, ...)]`.
|
||||||
|
if is_crate_root {
|
||||||
|
for &item in items {
|
||||||
|
let ModItem::ExternCrate(id) = item else { continue; };
|
||||||
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
||||||
|
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
||||||
let import = &self.item_tree[id];
|
let import = &self.item_tree[id];
|
||||||
let attrs = self.item_tree.attrs(
|
let attrs = self.item_tree.attrs(
|
||||||
self.def_collector.db,
|
self.def_collector.db,
|
||||||
|
|
|
@ -385,7 +385,7 @@ impl DefMap {
|
||||||
// Resolve in:
|
// Resolve in:
|
||||||
// - legacy scope of macro
|
// - legacy scope of macro
|
||||||
// - current module / scope
|
// - current module / scope
|
||||||
// - extern prelude
|
// - extern prelude / macro_use prelude
|
||||||
// - std prelude
|
// - std prelude
|
||||||
let from_legacy_macro = self[module]
|
let from_legacy_macro = self[module]
|
||||||
.scope
|
.scope
|
||||||
|
@ -414,9 +414,18 @@ impl DefMap {
|
||||||
.get(name)
|
.get(name)
|
||||||
.map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
|
.map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
|
||||||
};
|
};
|
||||||
|
let macro_use_prelude = || {
|
||||||
|
self.macro_use_prelude
|
||||||
|
.get(name)
|
||||||
|
.map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public))
|
||||||
|
};
|
||||||
let prelude = || self.resolve_in_prelude(db, name);
|
let prelude = || self.resolve_in_prelude(db, name);
|
||||||
|
|
||||||
from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude)
|
from_legacy_macro
|
||||||
|
.or(from_scope_or_builtin)
|
||||||
|
.or_else(extern_prelude)
|
||||||
|
.or_else(macro_use_prelude)
|
||||||
|
.or_else(prelude)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_name_in_crate_root_or_extern_prelude(
|
fn resolve_name_in_crate_root_or_extern_prelude(
|
||||||
|
|
|
@ -1216,17 +1216,58 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
let root = &def_map[def_map.root()].scope;
|
let root_module = &def_map[def_map.root()].scope;
|
||||||
let actual = root
|
assert!(
|
||||||
.legacy_macros()
|
root_module.legacy_macros().count() == 0,
|
||||||
.sorted_by(|a, b| std::cmp::Ord::cmp(&a.0, &b.0))
|
"`#[macro_use]` shouldn't bring macros into textual macro scope",
|
||||||
.map(|(name, _)| format!("{name}\n"))
|
);
|
||||||
.collect::<String>();
|
|
||||||
|
let actual = def_map.macro_use_prelude.iter().map(|(name, _)| name).sorted().join("\n");
|
||||||
|
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
legacy
|
legacy
|
||||||
macro20
|
macro20
|
||||||
proc_attr
|
proc_attr"#]]
|
||||||
"#]]
|
|
||||||
.assert_eq(&actual);
|
.assert_eq(&actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_prelude_macros_take_precedence_over_macro_use_prelude() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs edition:2021 crate:lib deps:dep,core
|
||||||
|
#[macro_use]
|
||||||
|
extern crate dep;
|
||||||
|
|
||||||
|
macro foo() { struct Ok; }
|
||||||
|
macro bar() { fn ok() {} }
|
||||||
|
|
||||||
|
foo!();
|
||||||
|
bar!();
|
||||||
|
|
||||||
|
//- /dep.rs crate:dep
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! foo {
|
||||||
|
() => { struct NotOk; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /core.rs crate:core
|
||||||
|
pub mod prelude {
|
||||||
|
pub mod rust_2021 {
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! bar {
|
||||||
|
() => { fn not_ok() {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
crate
|
||||||
|
Ok: t v
|
||||||
|
bar: m
|
||||||
|
dep: t
|
||||||
|
foo: m
|
||||||
|
ok: v
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue