mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Auto merge of #15422 - Veykril:import-sources, r=Veykril
internal: Record import source IDs cc https://github.com/rust-lang/rust-analyzer/issues/14079
This commit is contained in:
commit
b78d69c795
7 changed files with 220 additions and 185 deletions
|
@ -487,7 +487,7 @@ impl ExternCrateDeclData {
|
|||
db.crate_def_map(loc.container.krate())
|
||||
.extern_prelude()
|
||||
.find(|&(prelude_name, ..)| *prelude_name == name)
|
||||
.map(|(_, root)| root.krate())
|
||||
.map(|(_, (root, _))| root.krate())
|
||||
};
|
||||
|
||||
Arc::new(Self {
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
nameres::DefMap,
|
||||
path::{ModPath, PathKind},
|
||||
visibility::Visibility,
|
||||
ModuleDefId, ModuleId,
|
||||
CrateRootModuleId, ModuleDefId, ModuleId,
|
||||
};
|
||||
|
||||
/// Find a path that can be used to refer to a certain item. This can depend on
|
||||
|
@ -81,7 +81,7 @@ fn find_path_inner(
|
|||
}
|
||||
|
||||
let def_map = from.def_map(db);
|
||||
let crate_root = def_map.crate_root().into();
|
||||
let crate_root = def_map.crate_root();
|
||||
// - if the item is a module, jump straight to module search
|
||||
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
|
||||
let mut visited_modules = FxHashSet::default();
|
||||
|
@ -149,7 +149,7 @@ fn find_path_for_module(
|
|||
db: &dyn DefDatabase,
|
||||
def_map: &DefMap,
|
||||
visited_modules: &mut FxHashSet<ModuleId>,
|
||||
crate_root: ModuleId,
|
||||
crate_root: CrateRootModuleId,
|
||||
from: ModuleId,
|
||||
module_id: ModuleId,
|
||||
max_len: usize,
|
||||
|
@ -183,7 +183,7 @@ fn find_path_for_module(
|
|||
|
||||
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
|
||||
let root_def_map = crate_root.def_map(db);
|
||||
for (name, def_id) in root_def_map.extern_prelude() {
|
||||
for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() {
|
||||
if module_id == def_id {
|
||||
let name = scope_name.unwrap_or_else(|| name.clone());
|
||||
|
||||
|
@ -192,7 +192,7 @@ fn find_path_for_module(
|
|||
def_map[local_id]
|
||||
.scope
|
||||
.type_(&name)
|
||||
.filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
|
||||
.filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id.into()))
|
||||
})
|
||||
.is_some();
|
||||
let kind = if name_already_occupied_in_type_ns {
|
||||
|
@ -244,7 +244,7 @@ fn find_in_prelude(
|
|||
item: ItemInNs,
|
||||
from: ModuleId,
|
||||
) -> Option<ModPath> {
|
||||
let prelude_module = root_def_map.prelude()?;
|
||||
let (prelude_module, _) = root_def_map.prelude()?;
|
||||
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
|
||||
let prelude_def_map = prelude_module.def_map(db);
|
||||
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
|
||||
|
@ -293,7 +293,7 @@ fn calculate_best_path(
|
|||
db: &dyn DefDatabase,
|
||||
def_map: &DefMap,
|
||||
visited_modules: &mut FxHashSet<ModuleId>,
|
||||
crate_root: ModuleId,
|
||||
crate_root: CrateRootModuleId,
|
||||
max_len: usize,
|
||||
item: ItemInNs,
|
||||
from: ModuleId,
|
||||
|
|
|
@ -109,6 +109,17 @@ impl CrateRootModuleId {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq<ModuleId> for CrateRootModuleId {
|
||||
fn eq(&self, other: &ModuleId) -> bool {
|
||||
other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
|
||||
}
|
||||
}
|
||||
impl PartialEq<CrateRootModuleId> for ModuleId {
|
||||
fn eq(&self, other: &CrateRootModuleId) -> bool {
|
||||
other == self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CrateRootModuleId> for ModuleId {
|
||||
fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
|
||||
ModuleId { krate, block: None, local_id: DefMap::ROOT }
|
||||
|
|
|
@ -77,8 +77,8 @@ use crate::{
|
|||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
visibility::Visibility,
|
||||
AstId, BlockId, BlockLoc, CrateRootModuleId, FunctionId, LocalModuleId, Lookup, MacroExpander,
|
||||
MacroId, ModuleId, ProcMacroId,
|
||||
AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
|
||||
MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||
};
|
||||
|
||||
/// Contains the results of (early) name resolution.
|
||||
|
@ -105,10 +105,10 @@ pub struct DefMap {
|
|||
/// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
|
||||
/// but that attribute is nightly and when used in a block, it affects resolution globally
|
||||
/// so we aren't handling this correctly anyways).
|
||||
prelude: Option<ModuleId>,
|
||||
prelude: Option<(ModuleId, Option<UseId>)>,
|
||||
/// `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>,
|
||||
macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
|
||||
|
||||
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
|
||||
/// attributes.
|
||||
|
@ -125,7 +125,7 @@ pub struct DefMap {
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct DefMapCrateData {
|
||||
/// The extern prelude which contains all root modules of external crates that are in scope.
|
||||
extern_prelude: FxHashMap<Name, CrateRootModuleId>,
|
||||
extern_prelude: FxHashMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
|
||||
|
||||
/// Side table for resolving derive helpers.
|
||||
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
|
||||
|
@ -427,15 +427,19 @@ impl DefMap {
|
|||
self.block.map(|block| block.block)
|
||||
}
|
||||
|
||||
pub(crate) fn prelude(&self) -> Option<ModuleId> {
|
||||
pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
|
||||
self.prelude
|
||||
}
|
||||
|
||||
pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, ModuleId)> + '_ {
|
||||
self.data.extern_prelude.iter().map(|(name, &def)| (name, def.into()))
|
||||
pub(crate) fn extern_prelude(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ {
|
||||
self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
|
||||
}
|
||||
|
||||
pub(crate) fn macro_use_prelude(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
|
||||
pub(crate) fn macro_use_prelude(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
|
||||
self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
|
||||
}
|
||||
|
||||
|
|
|
@ -52,10 +52,10 @@ use crate::{
|
|||
tt,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
|
||||
ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
|
||||
LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc,
|
||||
ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc,
|
||||
TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseLoc,
|
||||
ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
|
||||
ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
|
||||
MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc,
|
||||
TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
|
||||
};
|
||||
|
||||
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
|
||||
|
@ -146,8 +146,8 @@ impl PartialResolvedImport {
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
enum ImportSource {
|
||||
Use { id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree> },
|
||||
ExternCrate(ItemTreeId<item_tree::ExternCrate>),
|
||||
Use { use_tree: Idx<ast::UseTree>, id: UseId, is_prelude: bool },
|
||||
ExternCrate { id: ExternCrateId },
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
|
@ -157,52 +157,42 @@ struct Import {
|
|||
visibility: RawVisibility,
|
||||
kind: ImportKind,
|
||||
source: ImportSource,
|
||||
is_prelude: bool,
|
||||
is_macro_use: bool,
|
||||
}
|
||||
|
||||
impl Import {
|
||||
fn from_use(
|
||||
db: &dyn DefDatabase,
|
||||
krate: CrateId,
|
||||
tree: &ItemTree,
|
||||
id: ItemTreeId<item_tree::Use>,
|
||||
item_tree_id: ItemTreeId<item_tree::Use>,
|
||||
id: UseId,
|
||||
is_prelude: bool,
|
||||
mut cb: impl FnMut(Self),
|
||||
) {
|
||||
let it = &tree[id.value];
|
||||
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
|
||||
let it = &tree[item_tree_id.value];
|
||||
let visibility = &tree[it.visibility];
|
||||
let is_prelude = attrs.by_key("prelude_import").exists();
|
||||
it.use_tree.expand(|idx, path, kind, alias| {
|
||||
cb(Self {
|
||||
path,
|
||||
alias,
|
||||
visibility: visibility.clone(),
|
||||
kind,
|
||||
is_prelude,
|
||||
is_macro_use: false,
|
||||
source: ImportSource::Use { id, use_tree: idx },
|
||||
source: ImportSource::Use { use_tree: idx, id, is_prelude },
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn from_extern_crate(
|
||||
db: &dyn DefDatabase,
|
||||
krate: CrateId,
|
||||
tree: &ItemTree,
|
||||
id: ItemTreeId<item_tree::ExternCrate>,
|
||||
item_tree_id: ItemTreeId<item_tree::ExternCrate>,
|
||||
id: ExternCrateId,
|
||||
) -> Self {
|
||||
let it = &tree[id.value];
|
||||
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
|
||||
let it = &tree[item_tree_id.value];
|
||||
let visibility = &tree[it.visibility];
|
||||
Self {
|
||||
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
|
||||
alias: it.alias.clone(),
|
||||
visibility: visibility.clone(),
|
||||
kind: ImportKind::Plain,
|
||||
is_prelude: false,
|
||||
is_macro_use: attrs.by_key("macro_use").exists(),
|
||||
source: ImportSource::ExternCrate(id),
|
||||
source: ImportSource::ExternCrate { id },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +270,7 @@ impl DefCollector<'_> {
|
|||
if dep.is_prelude() {
|
||||
crate_data
|
||||
.extern_prelude
|
||||
.insert(name.clone(), CrateRootModuleId { krate: dep.crate_id });
|
||||
.insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,7 +547,7 @@ impl DefCollector<'_> {
|
|||
|
||||
match per_ns.types {
|
||||
Some((ModuleDefId::ModuleId(m), _)) => {
|
||||
self.def_map.prelude = Some(m);
|
||||
self.def_map.prelude = Some((m, None));
|
||||
}
|
||||
types => {
|
||||
tracing::debug!(
|
||||
|
@ -720,7 +710,13 @@ impl DefCollector<'_> {
|
|||
/// 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
|
||||
/// created by `use` in the root module, ignoring the visibility of `use`.
|
||||
fn import_macros_from_extern_crate(&mut self, krate: CrateId, names: Option<Vec<Name>>) {
|
||||
fn import_macros_from_extern_crate(
|
||||
&mut self,
|
||||
krate: CrateId,
|
||||
names: Option<Vec<Name>>,
|
||||
|
||||
extern_crate: Option<ExternCrateId>,
|
||||
) {
|
||||
let def_map = self.db.crate_def_map(krate);
|
||||
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
|
||||
// macros.
|
||||
|
@ -729,12 +725,12 @@ impl DefCollector<'_> {
|
|||
for name in names {
|
||||
// FIXME: Report diagnostic on 404.
|
||||
if let Some(def) = root_scope.get(&name).take_macros() {
|
||||
self.def_map.macro_use_prelude.insert(name, def);
|
||||
self.def_map.macro_use_prelude.insert(name, (def, extern_crate));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (name, def) in root_scope.macros() {
|
||||
self.def_map.macro_use_prelude.insert(name.clone(), def);
|
||||
self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -771,48 +767,52 @@ impl DefCollector<'_> {
|
|||
let _p = profile::span("resolve_import")
|
||||
.detail(|| format!("{}", import.path.display(self.db.upcast())));
|
||||
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
|
||||
if matches!(import.source, ImportSource::ExternCrate { .. }) {
|
||||
let name = import
|
||||
.path
|
||||
.as_ident()
|
||||
.expect("extern crate should have been desugared to one-element path");
|
||||
match import.source {
|
||||
ImportSource::ExternCrate { .. } => {
|
||||
let name = import
|
||||
.path
|
||||
.as_ident()
|
||||
.expect("extern crate should have been desugared to one-element path");
|
||||
|
||||
let res = self.resolve_extern_crate(name);
|
||||
let res = self.resolve_extern_crate(name);
|
||||
|
||||
match res {
|
||||
Some(res) => {
|
||||
PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
|
||||
}
|
||||
None => PartialResolvedImport::Unresolved,
|
||||
}
|
||||
} else {
|
||||
let res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
ResolveMode::Import,
|
||||
module_id,
|
||||
&import.path,
|
||||
BuiltinShadowMode::Module,
|
||||
None, // An import may resolve to any kind of macro.
|
||||
);
|
||||
|
||||
let def = res.resolved_def;
|
||||
if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
|
||||
return PartialResolvedImport::Unresolved;
|
||||
}
|
||||
|
||||
if let Some(krate) = res.krate {
|
||||
if krate != self.def_map.krate {
|
||||
return PartialResolvedImport::Resolved(
|
||||
def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
||||
);
|
||||
match res {
|
||||
Some(res) => PartialResolvedImport::Resolved(PerNs::types(
|
||||
res.into(),
|
||||
Visibility::Public,
|
||||
)),
|
||||
None => PartialResolvedImport::Unresolved,
|
||||
}
|
||||
}
|
||||
ImportSource::Use { .. } => {
|
||||
let res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
ResolveMode::Import,
|
||||
module_id,
|
||||
&import.path,
|
||||
BuiltinShadowMode::Module,
|
||||
None, // An import may resolve to any kind of macro.
|
||||
);
|
||||
|
||||
// Check whether all namespaces are resolved.
|
||||
if def.is_full() {
|
||||
PartialResolvedImport::Resolved(def)
|
||||
} else {
|
||||
PartialResolvedImport::Indeterminate(def)
|
||||
let def = res.resolved_def;
|
||||
if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
|
||||
return PartialResolvedImport::Unresolved;
|
||||
}
|
||||
|
||||
if let Some(krate) = res.krate {
|
||||
if krate != self.def_map.krate {
|
||||
return PartialResolvedImport::Resolved(
|
||||
def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether all namespaces are resolved.
|
||||
if def.is_full() {
|
||||
PartialResolvedImport::Resolved(def)
|
||||
} else {
|
||||
PartialResolvedImport::Indeterminate(def)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -859,17 +859,17 @@ impl DefCollector<'_> {
|
|||
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
||||
|
||||
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
|
||||
if matches!(import.source, ImportSource::ExternCrate { .. })
|
||||
&& self.def_map.block.is_none()
|
||||
&& module_id == DefMap::ROOT
|
||||
{
|
||||
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
|
||||
{
|
||||
if let Ok(def) = def.try_into() {
|
||||
Arc::get_mut(&mut self.def_map.data)
|
||||
.unwrap()
|
||||
.extern_prelude
|
||||
.insert(name.clone(), def);
|
||||
if let ImportSource::ExternCrate { id, .. } = import.source {
|
||||
if self.def_map.block.is_none() && module_id == DefMap::ROOT {
|
||||
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) =
|
||||
(def.take_types(), name)
|
||||
{
|
||||
if let Ok(def) = def.try_into() {
|
||||
Arc::get_mut(&mut self.def_map.data)
|
||||
.unwrap()
|
||||
.extern_prelude
|
||||
.insert(name.clone(), (def, Some(id)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -880,11 +880,11 @@ impl DefCollector<'_> {
|
|||
tracing::debug!("glob import: {:?}", import);
|
||||
match def.take_types() {
|
||||
Some(ModuleDefId::ModuleId(m)) => {
|
||||
if import.is_prelude {
|
||||
if let ImportSource::Use { id, is_prelude: true, .. } = import.source {
|
||||
// Note: This dodgily overrides the injected prelude. The rustc
|
||||
// implementation seems to work the same though.
|
||||
cov_mark::hit!(std_prelude);
|
||||
self.def_map.prelude = Some(m);
|
||||
self.def_map.prelude = Some((m, Some(id)));
|
||||
} else if m.krate != self.def_map.krate {
|
||||
cov_mark::hit!(glob_across_crates);
|
||||
// glob import from other crate => we can just import everything once
|
||||
|
@ -1460,31 +1460,32 @@ impl DefCollector<'_> {
|
|||
// heuristic, but it works in practice.
|
||||
let mut diagnosed_extern_crates = FxHashSet::default();
|
||||
for directive in &self.unresolved_imports {
|
||||
if let ImportSource::ExternCrate(krate) = directive.import.source {
|
||||
let item_tree = krate.item_tree(self.db);
|
||||
let extern_crate = &item_tree[krate.value];
|
||||
if let ImportSource::ExternCrate { id } = directive.import.source {
|
||||
let item_tree_id = self.db.lookup_intern_extern_crate(id).id;
|
||||
let item_tree = item_tree_id.item_tree(self.db);
|
||||
let extern_crate = &item_tree[item_tree_id.value];
|
||||
|
||||
diagnosed_extern_crates.insert(extern_crate.name.clone());
|
||||
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
|
||||
directive.module_id,
|
||||
InFile::new(krate.file_id(), extern_crate.ast_id),
|
||||
InFile::new(item_tree_id.file_id(), extern_crate.ast_id),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
for directive in &self.unresolved_imports {
|
||||
if let ImportSource::Use { id: import, use_tree } = directive.import.source {
|
||||
if let ImportSource::Use { use_tree, id, is_prelude: _ } = directive.import.source {
|
||||
if matches!(
|
||||
(directive.import.path.segments().first(), &directive.import.path.kind),
|
||||
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let item_tree_id = self.db.lookup_intern_use(id).id;
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
|
||||
directive.module_id,
|
||||
import,
|
||||
item_tree_id,
|
||||
use_tree,
|
||||
));
|
||||
}
|
||||
|
@ -1519,72 +1520,66 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
|
||||
|
||||
// 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, _use)) = self.def_collector.def_map.prelude {
|
||||
if prelude_module.krate != krate && is_crate_root {
|
||||
cov_mark::hit!(prelude_is_macro_use);
|
||||
self.def_collector.import_macros_from_extern_crate(prelude_module.krate, None);
|
||||
self.def_collector.import_macros_from_extern_crate(
|
||||
prelude_module.krate,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
let db = self.def_collector.db;
|
||||
let module_id = self.module_id;
|
||||
let update_def =
|
||||
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
|
||||
def_collector.def_map.modules[module_id].scope.declare(id);
|
||||
def_collector.update(
|
||||
module_id,
|
||||
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
|
||||
vis,
|
||||
ImportType::Named,
|
||||
)
|
||||
};
|
||||
let resolve_vis = |def_map: &DefMap, visibility| {
|
||||
def_map
|
||||
.resolve_visibility(db, module_id, visibility, false)
|
||||
.unwrap_or(Visibility::Public)
|
||||
};
|
||||
|
||||
// This should be processed eagerly instead of deferred to resolving.
|
||||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
//
|
||||
// If we're not at the crate root, `macro_use`d extern crates are an error so let's just
|
||||
// ignore them.
|
||||
if is_crate_root {
|
||||
for &item in items {
|
||||
if let ModItem::ExternCrate(id) = item {
|
||||
self.process_macro_use_extern_crate(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &item in items {
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
||||
let mut process_mod_item = |item: ModItem| {
|
||||
let attrs = self.item_tree.attrs(db, krate, item.into());
|
||||
if let Some(cfg) = attrs.cfg() {
|
||||
if !self.is_cfg_enabled(&cfg) {
|
||||
self.emit_unconfigured_diagnostic(item, &cfg);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(()) = self.resolve_attributes(&attrs, item, container) {
|
||||
// Do not process the item. It has at least one non-builtin attribute, so the
|
||||
// fixed-point algorithm is required to resolve the rest of them.
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
let db = self.def_collector.db;
|
||||
let module = self.def_collector.def_map.module_id(self.module_id);
|
||||
let module = self.def_collector.def_map.module_id(module_id);
|
||||
let def_map = &mut self.def_collector.def_map;
|
||||
let update_def =
|
||||
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
|
||||
def_collector.def_map.modules[self.module_id].scope.declare(id);
|
||||
def_collector.update(
|
||||
self.module_id,
|
||||
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
|
||||
vis,
|
||||
ImportType::Named,
|
||||
)
|
||||
};
|
||||
let resolve_vis = |def_map: &DefMap, visibility| {
|
||||
def_map
|
||||
.resolve_visibility(db, self.module_id, visibility, false)
|
||||
.unwrap_or(Visibility::Public)
|
||||
};
|
||||
|
||||
match item {
|
||||
ModItem::Mod(m) => self.collect_module(m, &attrs),
|
||||
ModItem::Use(import_id) => {
|
||||
let _import_id =
|
||||
UseLoc { container: module, id: ItemTreeId::new(self.tree_id, import_id) }
|
||||
.intern(db);
|
||||
ModItem::Use(item_tree_id) => {
|
||||
let id = UseLoc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
}
|
||||
.intern(db);
|
||||
let is_prelude = attrs.by_key("prelude_import").exists();
|
||||
Import::from_use(
|
||||
db,
|
||||
krate,
|
||||
self.item_tree,
|
||||
ItemTreeId::new(self.tree_id, import_id),
|
||||
ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
id,
|
||||
is_prelude,
|
||||
|import| {
|
||||
self.def_collector.unresolved_imports.push(ImportDirective {
|
||||
module_id: self.module_id,
|
||||
|
@ -1594,22 +1589,29 @@ impl ModCollector<'_, '_> {
|
|||
},
|
||||
)
|
||||
}
|
||||
ModItem::ExternCrate(import_id) => {
|
||||
let extern_crate_id = ExternCrateLoc {
|
||||
ModItem::ExternCrate(item_tree_id) => {
|
||||
let id = ExternCrateLoc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, import_id),
|
||||
id: ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
}
|
||||
.intern(db);
|
||||
if is_crate_root {
|
||||
self.process_macro_use_extern_crate(
|
||||
item_tree_id,
|
||||
id,
|
||||
attrs.by_key("macro_use").attrs(),
|
||||
);
|
||||
}
|
||||
|
||||
self.def_collector.def_map.modules[self.module_id]
|
||||
.scope
|
||||
.define_extern_crate_decl(extern_crate_id);
|
||||
.define_extern_crate_decl(id);
|
||||
self.def_collector.unresolved_imports.push(ImportDirective {
|
||||
module_id: self.module_id,
|
||||
import: Import::from_extern_crate(
|
||||
db,
|
||||
krate,
|
||||
self.item_tree,
|
||||
ItemTreeId::new(self.tree_id, import_id),
|
||||
ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
id,
|
||||
),
|
||||
status: PartialResolvedImport::Unresolved,
|
||||
})
|
||||
|
@ -1768,21 +1770,34 @@ impl ModCollector<'_, '_> {
|
|||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// extern crates should be processed eagerly instead of deferred to resolving.
|
||||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
if is_crate_root {
|
||||
items
|
||||
.iter()
|
||||
.filter(|it| matches!(it, ModItem::ExternCrate(..)))
|
||||
.copied()
|
||||
.for_each(&mut process_mod_item);
|
||||
items
|
||||
.iter()
|
||||
.filter(|it| !matches!(it, ModItem::ExternCrate(..)))
|
||||
.copied()
|
||||
.for_each(process_mod_item);
|
||||
} else {
|
||||
items.iter().copied().for_each(process_mod_item);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_macro_use_extern_crate(&mut self, extern_crate: FileItemTreeId<ExternCrate>) {
|
||||
fn process_macro_use_extern_crate<'a>(
|
||||
&mut self,
|
||||
extern_crate: FileItemTreeId<ExternCrate>,
|
||||
extern_crate_id: ExternCrateId,
|
||||
macro_use_attrs: impl Iterator<Item = &'a Attr>,
|
||||
) {
|
||||
let db = self.def_collector.db;
|
||||
let attrs = self.item_tree.attrs(
|
||||
db,
|
||||
self.def_collector.def_map.krate,
|
||||
ModItem::from(extern_crate).into(),
|
||||
);
|
||||
if let Some(cfg) = attrs.cfg() {
|
||||
if !self.is_cfg_enabled(&cfg) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let target_crate =
|
||||
match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) {
|
||||
|
@ -1798,11 +1813,11 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
let mut single_imports = Vec::new();
|
||||
let hygiene = Hygiene::new_unhygienic();
|
||||
for attr in attrs.by_key("macro_use").attrs() {
|
||||
for attr in macro_use_attrs {
|
||||
let Some(paths) = attr.parse_path_comma_token_tree(db.upcast(), &hygiene) else {
|
||||
// `#[macro_use]` (without any paths) found, forget collected names and just import
|
||||
// all visible macros.
|
||||
self.def_collector.import_macros_from_extern_crate(target_crate, None);
|
||||
self.def_collector.import_macros_from_extern_crate(target_crate, None, Some(extern_crate_id));
|
||||
return;
|
||||
};
|
||||
for path in paths {
|
||||
|
@ -1812,7 +1827,11 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
self.def_collector.import_macros_from_extern_crate(target_crate, Some(single_imports));
|
||||
self.def_collector.import_macros_from_extern_crate(
|
||||
target_crate,
|
||||
Some(single_imports),
|
||||
Some(extern_crate_id),
|
||||
);
|
||||
}
|
||||
|
||||
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
|
||||
|
@ -2198,7 +2217,7 @@ impl ModCollector<'_, '_> {
|
|||
map[module].scope.get_legacy_macro(name)?.last().copied()
|
||||
})
|
||||
.or_else(|| def_map[self.module_id].scope.get(name).take_macros())
|
||||
.or_else(|| def_map.macro_use_prelude.get(name).copied())
|
||||
.or_else(|| Some(def_map.macro_use_prelude.get(name).copied()?.0))
|
||||
.filter(|&id| {
|
||||
sub_namespace_match(
|
||||
Some(MacroSubNs::from_id(db, id)),
|
||||
|
|
|
@ -299,7 +299,7 @@ impl DefMap {
|
|||
Some((_, segment)) => segment,
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
if let Some(&def) = self.data.extern_prelude.get(segment) {
|
||||
if let Some(&(def, _extern_crate)) = self.data.extern_prelude.get(segment) {
|
||||
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
|
||||
PerNs::types(def.into(), Visibility::Public)
|
||||
} else {
|
||||
|
@ -452,15 +452,14 @@ impl DefMap {
|
|||
// Don't resolve extern prelude in block `DefMap`s.
|
||||
return PerNs::none();
|
||||
}
|
||||
self.data
|
||||
.extern_prelude
|
||||
.get(name)
|
||||
.map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
|
||||
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
|
||||
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))
|
||||
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
|
||||
PerNs::macros(it.into(), Visibility::Public)
|
||||
})
|
||||
};
|
||||
let prelude = || self.resolve_in_prelude(db, name);
|
||||
|
||||
|
@ -492,14 +491,16 @@ impl DefMap {
|
|||
.extern_prelude
|
||||
.get(name)
|
||||
.copied()
|
||||
.map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public))
|
||||
.map_or(PerNs::none(), |(it, _extern_crate)| {
|
||||
PerNs::types(it.into(), Visibility::Public)
|
||||
})
|
||||
};
|
||||
|
||||
from_crate_root.or_else(from_extern_prelude)
|
||||
}
|
||||
|
||||
fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
|
||||
if let Some(prelude) = self.prelude {
|
||||
if let Some((prelude, _use)) = self.prelude {
|
||||
let keep;
|
||||
let def_map = if prelude.krate == self.krate {
|
||||
self
|
||||
|
|
|
@ -433,16 +433,16 @@ impl Resolver {
|
|||
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
|
||||
})
|
||||
});
|
||||
def_map.macro_use_prelude().for_each(|(name, def)| {
|
||||
def_map.macro_use_prelude().for_each(|(name, (def, _extern_crate))| {
|
||||
res.add(name, ScopeDef::ModuleDef(def.into()));
|
||||
});
|
||||
def_map.extern_prelude().for_each(|(name, def)| {
|
||||
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
|
||||
def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
|
||||
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
|
||||
});
|
||||
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
|
||||
res.add_per_ns(name, def);
|
||||
});
|
||||
if let Some(prelude) = def_map.prelude() {
|
||||
if let Some((prelude, _use)) = def_map.prelude() {
|
||||
let prelude_def_map = prelude.def_map(db);
|
||||
for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
|
||||
res.add_per_ns(name, def)
|
||||
|
@ -473,7 +473,7 @@ impl Resolver {
|
|||
}
|
||||
|
||||
// Fill in the prelude traits
|
||||
if let Some(prelude) = self.module_scope.def_map.prelude() {
|
||||
if let Some((prelude, _use)) = self.module_scope.def_map.prelude() {
|
||||
let prelude_def_map = prelude.def_map(db);
|
||||
traits.extend(prelude_def_map[prelude.local_id].scope.traits());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue