This commit is contained in:
Lukas Wirth 2023-08-09 15:54:10 +02:00
parent 992b928a93
commit c516dd51e9

View File

@ -147,8 +147,16 @@ fn namespaces(self) -> PerNs {
// FIXME: `item_tree_id` can be derived from `id`, look into deduplicating this // FIXME: `item_tree_id` can be derived from `id`, look into deduplicating this
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
enum ImportSource { enum ImportSource {
Use { item_tree_id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree>, id: UseId }, Use {
ExternCrate { item_tree_id: ItemTreeId<item_tree::ExternCrate>, id: ExternCrateId }, item_tree_id: ItemTreeId<item_tree::Use>,
use_tree: Idx<ast::UseTree>,
id: UseId,
is_prelude: bool,
},
ExternCrate {
item_tree_id: ItemTreeId<item_tree::ExternCrate>,
id: ExternCrateId,
},
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -158,53 +166,41 @@ struct Import {
visibility: RawVisibility, visibility: RawVisibility,
kind: ImportKind, kind: ImportKind,
source: ImportSource, source: ImportSource,
is_prelude: bool,
is_macro_use: bool,
} }
impl Import { impl Import {
fn from_use( fn from_use(
db: &dyn DefDatabase,
krate: CrateId,
tree: &ItemTree, tree: &ItemTree,
item_tree_id: ItemTreeId<item_tree::Use>, item_tree_id: ItemTreeId<item_tree::Use>,
id: UseId, id: UseId,
is_prelude: bool,
mut cb: impl FnMut(Self), mut cb: impl FnMut(Self),
) { ) {
let it = &tree[item_tree_id.value]; let it = &tree[item_tree_id.value];
let attrs = &tree.attrs(db, krate, ModItem::from(item_tree_id.value).into());
let visibility = &tree[it.visibility]; let visibility = &tree[it.visibility];
let is_prelude = attrs.by_key("prelude_import").exists();
it.use_tree.expand(|idx, path, kind, alias| { it.use_tree.expand(|idx, path, kind, alias| {
cb(Self { cb(Self {
path, path,
alias, alias,
visibility: visibility.clone(), visibility: visibility.clone(),
kind, kind,
is_prelude, source: ImportSource::Use { item_tree_id, use_tree: idx, id, is_prelude },
is_macro_use: false,
source: ImportSource::Use { item_tree_id, use_tree: idx, id },
}); });
}); });
} }
fn from_extern_crate( fn from_extern_crate(
db: &dyn DefDatabase,
krate: CrateId,
tree: &ItemTree, tree: &ItemTree,
item_tree_id: ItemTreeId<item_tree::ExternCrate>, item_tree_id: ItemTreeId<item_tree::ExternCrate>,
id: ExternCrateId, id: ExternCrateId,
) -> Self { ) -> Self {
let it = &tree[item_tree_id.value]; let it = &tree[item_tree_id.value];
let attrs = &tree.attrs(db, krate, ModItem::from(item_tree_id.value).into());
let visibility = &tree[it.visibility]; let visibility = &tree[it.visibility];
Self { Self {
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
alias: it.alias.clone(), alias: it.alias.clone(),
visibility: visibility.clone(), visibility: visibility.clone(),
kind: ImportKind::Plain, kind: ImportKind::Plain,
is_prelude: false,
is_macro_use: attrs.by_key("macro_use").exists(),
source: ImportSource::ExternCrate { item_tree_id, id }, source: ImportSource::ExternCrate { item_tree_id, id },
} }
} }
@ -893,17 +889,11 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
tracing::debug!("glob import: {:?}", import); tracing::debug!("glob import: {:?}", import);
match def.take_types() { match def.take_types() {
Some(ModuleDefId::ModuleId(m)) => { 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 // Note: This dodgily overrides the injected prelude. The rustc
// implementation seems to work the same though. // implementation seems to work the same though.
cov_mark::hit!(std_prelude); cov_mark::hit!(std_prelude);
self.def_map.prelude = Some(( self.def_map.prelude = Some((m, Some(id)));
m,
match import.source {
ImportSource::Use { id, .. } => Some(id),
ImportSource::ExternCrate { .. } => None,
},
));
} else if m.krate != self.def_map.krate { } else if m.krate != self.def_map.krate {
cov_mark::hit!(glob_across_crates); cov_mark::hit!(glob_across_crates);
// glob import from other crate => we can just import everything once // glob import from other crate => we can just import everything once
@ -1493,7 +1483,9 @@ fn finish(mut self) -> DefMap {
} }
for directive in &self.unresolved_imports { for directive in &self.unresolved_imports {
if let ImportSource::Use { item_tree_id, use_tree, id: _ } = directive.import.source { if let ImportSource::Use { item_tree_id, use_tree, id: _, is_prelude: _ } =
directive.import.source
{
if matches!( if matches!(
(directive.import.path.segments().first(), &directive.import.path.kind), (directive.import.path.segments().first(), &directive.import.path.kind),
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate) (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
@ -1592,12 +1584,12 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
id: ItemTreeId::new(self.tree_id, item_tree_id), id: ItemTreeId::new(self.tree_id, item_tree_id),
} }
.intern(db); .intern(db);
let is_prelude = attrs.by_key("prelude_import").exists();
Import::from_use( Import::from_use(
db,
krate,
self.item_tree, self.item_tree,
ItemTreeId::new(self.tree_id, item_tree_id), ItemTreeId::new(self.tree_id, item_tree_id),
id, id,
is_prelude,
|import| { |import| {
self.def_collector.unresolved_imports.push(ImportDirective { self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id, module_id: self.module_id,
@ -1614,7 +1606,11 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
} }
.intern(db); .intern(db);
if is_crate_root { if is_crate_root {
self.process_macro_use_extern_crate(item_tree_id, id); 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] self.def_collector.def_map.modules[self.module_id]
@ -1623,8 +1619,6 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
self.def_collector.unresolved_imports.push(ImportDirective { self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id, module_id: self.module_id,
import: Import::from_extern_crate( import: Import::from_extern_crate(
db,
krate,
self.item_tree, self.item_tree,
ItemTreeId::new(self.tree_id, item_tree_id), ItemTreeId::new(self.tree_id, item_tree_id),
id, id,
@ -1807,22 +1801,13 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
} }
} }
fn process_macro_use_extern_crate( fn process_macro_use_extern_crate<'a>(
&mut self, &mut self,
extern_crate: FileItemTreeId<ExternCrate>, extern_crate: FileItemTreeId<ExternCrate>,
extern_crate_id: ExternCrateId, extern_crate_id: ExternCrateId,
macro_use_attrs: impl Iterator<Item = &'a Attr>,
) { ) {
let db = self.def_collector.db; 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 = let target_crate =
match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) { match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) {
@ -1838,7 +1823,7 @@ fn process_macro_use_extern_crate(
let mut single_imports = Vec::new(); let mut single_imports = Vec::new();
let hygiene = Hygiene::new_unhygienic(); 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 { 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 // `#[macro_use]` (without any paths) found, forget collected names and just import
// all visible macros. // all visible macros.