Skip to content

Commit 090a03a

Browse files
committed
Remove ImportSource::ExternCrate as the fixed point loop can't affect it
1 parent fe2b453 commit 090a03a

File tree

4 files changed

+102
-138
lines changed

4 files changed

+102
-138
lines changed

src/tools/rust-analyzer/crates/base-db/src/input.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ pub struct CrateData {
288288
/// The cfg options that could be used by the crate
289289
pub potential_cfg_options: Option<Arc<CfgOptions>>,
290290
pub env: Env,
291+
/// The dependencies of this crate.
292+
///
293+
/// Note that this may contain more dependencies than the crate actually uses.
294+
/// A common example is the test crate which is included but only actually is active when
295+
/// declared in source via `extern crate test`.
291296
pub dependencies: Vec<Dependency>,
292297
pub origin: CrateOrigin,
293298
pub is_proc_macro: bool,

src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs

Lines changed: 96 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use crate::{
3030
db::DefDatabase,
3131
item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
3232
item_tree::{
33-
self, AttrOwner, ExternCrate, FieldsShape, FileItemTreeId, ImportKind, ItemTree,
34-
ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
33+
self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
34+
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
3535
},
3636
macro_call_as_call_id, macro_call_as_call_id_with_eager,
3737
nameres::{
@@ -93,6 +93,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
9393
proc_macros,
9494
from_glob_import: Default::default(),
9595
skip_attrs: Default::default(),
96+
unresolved_extern_crates: Default::default(),
9697
is_proc_macro: krate.is_proc_macro,
9798
};
9899
if tree_id.is_block() {
@@ -128,7 +129,6 @@ impl PartialResolvedImport {
128129
#[derive(Clone, Debug, Eq, PartialEq)]
129130
enum ImportSource {
130131
Use { use_tree: Idx<ast::UseTree>, id: UseId, is_prelude: bool, kind: ImportKind },
131-
ExternCrate { id: ExternCrateId },
132132
}
133133

134134
#[derive(Debug, Eq, PartialEq)]
@@ -158,21 +158,6 @@ impl Import {
158158
});
159159
});
160160
}
161-
162-
fn from_extern_crate(
163-
tree: &ItemTree,
164-
item_tree_id: ItemTreeId<item_tree::ExternCrate>,
165-
id: ExternCrateId,
166-
) -> Self {
167-
let it = &tree[item_tree_id.value];
168-
let visibility = &tree[it.visibility];
169-
Self {
170-
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
171-
alias: it.alias.clone(),
172-
visibility: visibility.clone(),
173-
source: ImportSource::ExternCrate { id },
174-
}
175-
}
176161
}
177162

178163
#[derive(Debug, Eq, PartialEq)]
@@ -218,11 +203,16 @@ enum MacroDirectiveKind {
218203
struct DefCollector<'a> {
219204
db: &'a dyn DefDatabase,
220205
def_map: DefMap,
206+
// The dependencies of the current crate, including optional deps like `test`.
221207
deps: FxHashMap<Name, Dependency>,
222208
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
223209
unresolved_imports: Vec<ImportDirective>,
224210
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
225211
unresolved_macros: Vec<MacroDirective>,
212+
// We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
213+
// resolve. When we emit diagnostics for unresolved imports, we only do so if the import
214+
// doesn't start with an unresolved crate's name.
215+
unresolved_extern_crates: FxHashSet<Name>,
226216
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
227217
cfg_options: &'a CfgOptions,
228218
/// List of procedural macros defined by this crate. This is read from the dynamic library
@@ -310,6 +300,7 @@ impl DefCollector<'_> {
310300
}
311301

312302
for (name, dep) in &self.deps {
303+
// Add all
313304
if dep.is_prelude() {
314305
// This is a bit confusing but the gist is that `no_core` and `no_std` remove the
315306
// sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly
@@ -329,6 +320,7 @@ impl DefCollector<'_> {
329320
if skip {
330321
continue;
331322
}
323+
332324
crate_data
333325
.extern_prelude
334326
.insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
@@ -789,23 +781,6 @@ impl DefCollector<'_> {
789781
.entered();
790782
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
791783
match import.source {
792-
ImportSource::ExternCrate { .. } => {
793-
let name = import
794-
.path
795-
.as_ident()
796-
.expect("extern crate should have been desugared to one-element path");
797-
798-
let res = self.resolve_extern_crate(name);
799-
800-
match res {
801-
Some(res) => PartialResolvedImport::Resolved(PerNs::types(
802-
res.into(),
803-
Visibility::Public,
804-
None,
805-
)),
806-
None => PartialResolvedImport::Unresolved,
807-
}
808-
}
809784
ImportSource::Use { .. } => {
810785
let res = self.def_map.resolve_path_fp_with_macro(
811786
self.db,
@@ -837,15 +812,6 @@ impl DefCollector<'_> {
837812
}
838813
}
839814

840-
fn resolve_extern_crate(&self, name: &Name) -> Option<CrateRootModuleId> {
841-
if *name == sym::self_.clone() {
842-
cov_mark::hit!(extern_crate_self_as);
843-
Some(self.def_map.crate_root())
844-
} else {
845-
self.deps.get(name).map(|dep| CrateRootModuleId { krate: dep.crate_id })
846-
}
847-
}
848-
849815
fn record_resolved_import(&mut self, directive: &ImportDirective) {
850816
let _p = tracing::info_span!("record_resolved_import").entered();
851817

@@ -858,8 +824,7 @@ impl DefCollector<'_> {
858824
.unwrap_or(Visibility::Public);
859825

860826
match import.source {
861-
ImportSource::ExternCrate { .. }
862-
| ImportSource::Use { kind: ImportKind::Plain | ImportKind::TypeOnly, .. } => {
827+
ImportSource::Use { kind: ImportKind::Plain | ImportKind::TypeOnly, .. } => {
863828
let name = match &import.alias {
864829
Some(ImportAlias::Alias(name)) => Some(name),
865830
Some(ImportAlias::Underscore) => None,
@@ -873,22 +838,6 @@ impl DefCollector<'_> {
873838
};
874839

875840
let imp = match import.source {
876-
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
877-
ImportSource::ExternCrate { id, .. } => {
878-
if self.def_map.block.is_none() && module_id == DefMap::ROOT {
879-
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) =
880-
(def.take_types(), name)
881-
{
882-
if let Ok(def) = def.try_into() {
883-
Arc::get_mut(&mut self.def_map.data)
884-
.unwrap()
885-
.extern_prelude
886-
.insert(name.clone(), (def, Some(id)));
887-
}
888-
}
889-
}
890-
ImportType::ExternCrate(id)
891-
}
892841
ImportSource::Use { kind, id, use_tree, .. } => {
893842
if kind == ImportKind::TypeOnly {
894843
def.values = None;
@@ -1560,45 +1509,21 @@ impl DefCollector<'_> {
15601509
}
15611510

15621511
// Emit diagnostics for all remaining unresolved imports.
1563-
1564-
// We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
1565-
// resolve. We first emit diagnostics for unresolved extern crates and collect the missing
1566-
// crate names. Then we emit diagnostics for unresolved imports, but only if the import
1567-
// doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
1568-
// heuristic, but it works in practice.
1569-
let mut diagnosed_extern_crates = FxHashSet::default();
1570-
for directive in &self.unresolved_imports {
1571-
if let ImportSource::ExternCrate { id } = directive.import.source {
1572-
let item_tree_id = id.lookup(self.db).id;
1573-
let item_tree = item_tree_id.item_tree(self.db);
1574-
let extern_crate = &item_tree[item_tree_id.value];
1575-
1576-
diagnosed_extern_crates.insert(extern_crate.name.clone());
1577-
1578-
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
1579-
directive.module_id,
1580-
InFile::new(item_tree_id.file_id(), extern_crate.ast_id),
1581-
));
1582-
}
1583-
}
1584-
15851512
for directive in &self.unresolved_imports {
1586-
if let ImportSource::Use { use_tree, id, is_prelude: _, kind: _ } =
1587-
directive.import.source
1588-
{
1589-
if matches!(
1590-
(directive.import.path.segments().first(), &directive.import.path.kind),
1591-
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
1592-
) {
1593-
continue;
1594-
}
1595-
let item_tree_id = id.lookup(self.db).id;
1596-
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
1597-
directive.module_id,
1598-
item_tree_id,
1599-
use_tree,
1600-
));
1513+
let ImportSource::Use { use_tree, id, is_prelude: _, kind: _ } =
1514+
directive.import.source;
1515+
if matches!(
1516+
(directive.import.path.segments().first(), &directive.import.path.kind),
1517+
(Some(krate), PathKind::Plain | PathKind::Abs) if self.unresolved_extern_crates.contains(krate)
1518+
) {
1519+
continue;
16011520
}
1521+
let item_tree_id = id.lookup(self.db).id;
1522+
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
1523+
directive.module_id,
1524+
item_tree_id,
1525+
use_tree,
1526+
));
16021527
}
16031528

16041529
self.def_map
@@ -1623,7 +1548,8 @@ impl ModCollector<'_, '_> {
16231548

16241549
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
16251550
let krate = self.def_collector.def_map.krate;
1626-
let is_crate_root = self.module_id == DefMap::ROOT;
1551+
let is_crate_root =
1552+
self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none();
16271553

16281554
// Note: don't assert that inserted value is fresh: it's simply not true
16291555
// for macros.
@@ -1632,10 +1558,7 @@ impl ModCollector<'_, '_> {
16321558
// Prelude module is always considered to be `#[macro_use]`.
16331559
if let Some((prelude_module, _use)) = self.def_collector.def_map.prelude {
16341560
// Don't insert macros from the prelude into blocks, as they can be shadowed by other macros.
1635-
if prelude_module.krate != krate
1636-
&& is_crate_root
1637-
&& self.def_collector.def_map.block.is_none()
1638-
{
1561+
if prelude_module.krate != krate && is_crate_root {
16391562
cov_mark::hit!(prelude_is_macro_use);
16401563
self.def_collector.import_macros_from_extern_crate(
16411564
prelude_module.krate,
@@ -1709,26 +1632,73 @@ impl ModCollector<'_, '_> {
17091632
id: ItemTreeId::new(self.tree_id, item_tree_id),
17101633
}
17111634
.intern(db);
1712-
if is_crate_root {
1713-
self.process_macro_use_extern_crate(
1714-
item_tree_id,
1715-
id,
1716-
attrs.by_key(&sym::macro_use).attrs(),
1635+
def_map.modules[self.module_id].scope.define_extern_crate_decl(id);
1636+
1637+
let item_tree::ExternCrate { name, visibility, alias, ast_id } =
1638+
&self.item_tree[item_tree_id];
1639+
1640+
let is_self = *name == sym::self_;
1641+
let resolved = if is_self {
1642+
cov_mark::hit!(extern_crate_self_as);
1643+
Some(def_map.crate_root())
1644+
} else {
1645+
self.def_collector
1646+
.deps
1647+
.get(name)
1648+
.map(|dep| CrateRootModuleId { krate: dep.crate_id })
1649+
};
1650+
1651+
let name = match alias {
1652+
Some(ImportAlias::Alias(name)) => Some(name),
1653+
Some(ImportAlias::Underscore) => None,
1654+
None => Some(name),
1655+
};
1656+
1657+
if let Some(resolved) = resolved {
1658+
let vis = resolve_vis(def_map, &self.item_tree[*visibility]);
1659+
1660+
if is_crate_root {
1661+
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
1662+
if let Some(name) = name {
1663+
Arc::get_mut(&mut def_map.data)
1664+
.unwrap()
1665+
.extern_prelude
1666+
.insert(name.clone(), (resolved, Some(id)));
1667+
}
1668+
// they also allow `#[macro_use]`
1669+
if !is_self {
1670+
self.process_macro_use_extern_crate(
1671+
id,
1672+
attrs.by_key(&sym::macro_use).attrs(),
1673+
resolved.krate,
1674+
);
1675+
}
1676+
}
1677+
1678+
self.def_collector.update(
1679+
module_id,
1680+
&[(
1681+
name.cloned(),
1682+
PerNs::types(
1683+
resolved.into(),
1684+
vis,
1685+
Some(ImportOrExternCrate::ExternCrate(id)),
1686+
),
1687+
)],
1688+
vis,
1689+
Some(ImportType::ExternCrate(id)),
1690+
);
1691+
} else {
1692+
if let Some(name) = name {
1693+
self.def_collector.unresolved_extern_crates.insert(name.clone());
1694+
}
1695+
self.def_collector.def_map.diagnostics.push(
1696+
DefDiagnostic::unresolved_extern_crate(
1697+
module_id,
1698+
InFile::new(self.file_id(), *ast_id),
1699+
),
17171700
);
17181701
}
1719-
1720-
self.def_collector.def_map.modules[self.module_id]
1721-
.scope
1722-
.define_extern_crate_decl(id);
1723-
self.def_collector.unresolved_imports.push(ImportDirective {
1724-
module_id: self.module_id,
1725-
import: Import::from_extern_crate(
1726-
self.item_tree,
1727-
ItemTreeId::new(self.tree_id, item_tree_id),
1728-
id,
1729-
),
1730-
status: PartialResolvedImport::Unresolved,
1731-
})
17321702
}
17331703
ModItem::ExternBlock(block) => self.collect(
17341704
&self.item_tree[block].children,
@@ -1939,27 +1909,15 @@ impl ModCollector<'_, '_> {
19391909

19401910
fn process_macro_use_extern_crate<'a>(
19411911
&mut self,
1942-
extern_crate: FileItemTreeId<ExternCrate>,
19431912
extern_crate_id: ExternCrateId,
19441913
macro_use_attrs: impl Iterator<Item = &'a Attr>,
1914+
target_crate: CrateId,
19451915
) {
1946-
let db = self.def_collector.db;
1947-
1948-
let target_crate =
1949-
match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) {
1950-
Some(m) if m.krate == self.def_collector.def_map.krate => {
1951-
cov_mark::hit!(ignore_macro_use_extern_crate_self);
1952-
return;
1953-
}
1954-
Some(m) => m.krate,
1955-
None => return,
1956-
};
1957-
19581916
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
1959-
19601917
let mut single_imports = Vec::new();
19611918
for attr in macro_use_attrs {
1962-
let Some(paths) = attr.parse_path_comma_token_tree(db.upcast()) else {
1919+
let Some(paths) = attr.parse_path_comma_token_tree(self.def_collector.db.upcast())
1920+
else {
19631921
// `#[macro_use]` (without any paths) found, forget collected names and just import
19641922
// all visible macros.
19651923
self.def_collector.import_macros_from_extern_crate(
@@ -2523,6 +2481,7 @@ mod tests {
25232481
from_glob_import: Default::default(),
25242482
skip_attrs: Default::default(),
25252483
is_proc_macro: false,
2484+
unresolved_extern_crates: Default::default(),
25262485
};
25272486
collector.seed_with_top_level();
25282487
collector.collect();

src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,6 @@ pub struct Arc;
416416

417417
#[test]
418418
fn macro_use_extern_crate_self() {
419-
cov_mark::check!(ignore_macro_use_extern_crate_self);
420419
check(
421420
r#"
422421
//- /main.rs crate:main

src/tools/rust-analyzer/crates/ide/src/navigation_target.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ pub(crate) fn orig_range_with_focus_r(
792792
.definition_range(db)
793793
};
794794

795+
// FIXME: Also make use of the syntax context to determine which site we are at?
795796
let value_range = InFile::new(hir_file, value).original_node_file_range_opt(db);
796797
let ((call_site_range, call_site_focus), def_site) =
797798
match InFile::new(hir_file, name).original_node_file_range_opt(db) {

0 commit comments

Comments
 (0)