Skip to content

Commit 12cb6e7

Browse files
committed
Auto merge of #15377 - Veykril:extern-crate-decl, r=Veykril
Add ExternCrateDecl to HIR Adding these doesn't really require much design effort as they represent a single import, unlike use trees which are one item that represent 0 or more imports. We only resolve to this definition when actually resolving on the name or alias of an `extern crate name as alias` item, not usages yet as that requires far more changes that won't lead anywhere without giving it more thought. Nevertheless the changes slightly improve IDE things, an example being hover on the decl showing the merged doc comments for example. cc #14079
2 parents 8e18b0f + 6e2c3f6 commit 12cb6e7

40 files changed

+584
-166
lines changed

crates/hir-def/src/child_by_source.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::{
1414
item_scope::ItemScope,
1515
nameres::DefMap,
1616
src::{HasChildSource, HasSource},
17-
AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, MacroId,
18-
ModuleDefId, ModuleId, TraitId, VariantId,
17+
AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, ImplId,
18+
Lookup, MacroId, ModuleDefId, ModuleId, TraitId, VariantId,
1919
};
2020

2121
pub trait ChildBySource {
@@ -91,6 +91,7 @@ impl ChildBySource for ItemScope {
9191
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
9292
self.declarations().for_each(|item| add_module_def(db, res, file_id, item));
9393
self.impls().for_each(|imp| add_impl(db, res, file_id, imp));
94+
self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext));
9495
self.unnamed_consts().for_each(|konst| {
9596
let loc = konst.lookup(db);
9697
if loc.id.file_id() == file_id {
@@ -167,6 +168,17 @@ impl ChildBySource for ItemScope {
167168
map[keys::IMPL].insert(loc.source(db).value, imp)
168169
}
169170
}
171+
fn add_extern_crate(
172+
db: &dyn DefDatabase,
173+
map: &mut DynMap,
174+
file_id: HirFileId,
175+
ext: ExternCrateId,
176+
) {
177+
let loc = ext.lookup(db);
178+
if loc.id.file_id() == file_id {
179+
map[keys::EXTERN_CRATE].insert(loc.source(db).value, ext)
180+
}
181+
}
170182
}
171183
}
172184

crates/hir-def/src/data.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
pub mod adt;
44

5+
use base_db::CrateId;
56
use hir_expand::{
67
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
78
};
@@ -467,6 +468,7 @@ pub struct ExternCrateDeclData {
467468
pub name: Name,
468469
pub alias: Option<ImportAlias>,
469470
pub visibility: RawVisibility,
471+
pub crate_id: Option<CrateId>,
470472
}
471473

472474
impl ExternCrateDeclData {
@@ -478,10 +480,21 @@ impl ExternCrateDeclData {
478480
let item_tree = loc.id.item_tree(db);
479481
let extern_crate = &item_tree[loc.id.value];
480482

483+
let name = extern_crate.name.clone();
484+
let crate_id = if name == hir_expand::name![self] {
485+
Some(loc.container.krate())
486+
} else {
487+
db.crate_def_map(loc.container.krate())
488+
.extern_prelude()
489+
.find(|&(prelude_name, ..)| *prelude_name == name)
490+
.map(|(_, root)| root.krate())
491+
};
492+
481493
Arc::new(Self {
482494
name: extern_crate.name.clone(),
483495
visibility: item_tree[extern_crate.visibility].clone(),
484496
alias: extern_crate.alias.clone(),
497+
crate_id,
485498
})
486499
}
487500
}

crates/hir-def/src/item_scope.rs

+6
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ impl ItemScope {
113113
self.declarations.iter().copied()
114114
}
115115

116+
pub fn extern_crate_decls(
117+
&self,
118+
) -> impl Iterator<Item = ExternCrateId> + ExactSizeIterator + '_ {
119+
self.extern_crate_decls.iter().copied()
120+
}
121+
116122
pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
117123
self.impls.iter().copied()
118124
}

crates/hir-def/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ impl From<CrateRootModuleId> for ModuleDefId {
121121
}
122122
}
123123

124+
impl From<CrateId> for CrateRootModuleId {
125+
fn from(krate: CrateId) -> Self {
126+
CrateRootModuleId { krate }
127+
}
128+
}
129+
124130
impl TryFrom<ModuleId> for CrateRootModuleId {
125131
type Error = ();
126132

crates/hir-def/src/nameres/tests/incremental.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -213,17 +213,17 @@ pub type Ty = ();
213213

214214
for (_, res) in module_data.scope.resolutions() {
215215
match res.values.or(res.types).unwrap().0 {
216-
ModuleDefId::FunctionId(f) => drop(db.function_data(f)),
216+
ModuleDefId::FunctionId(f) => _ = db.function_data(f),
217217
ModuleDefId::AdtId(adt) => match adt {
218-
AdtId::StructId(it) => drop(db.struct_data(it)),
219-
AdtId::UnionId(it) => drop(db.union_data(it)),
220-
AdtId::EnumId(it) => drop(db.enum_data(it)),
218+
AdtId::StructId(it) => _ = db.struct_data(it),
219+
AdtId::UnionId(it) => _ = db.union_data(it),
220+
AdtId::EnumId(it) => _ = db.enum_data(it),
221221
},
222-
ModuleDefId::ConstId(it) => drop(db.const_data(it)),
223-
ModuleDefId::StaticId(it) => drop(db.static_data(it)),
224-
ModuleDefId::TraitId(it) => drop(db.trait_data(it)),
225-
ModuleDefId::TraitAliasId(it) => drop(db.trait_alias_data(it)),
226-
ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)),
222+
ModuleDefId::ConstId(it) => _ = db.const_data(it),
223+
ModuleDefId::StaticId(it) => _ = db.static_data(it),
224+
ModuleDefId::TraitId(it) => _ = db.trait_data(it),
225+
ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_data(it),
226+
ModuleDefId::TypeAliasId(it) => _ = db.type_alias_data(it),
227227
ModuleDefId::EnumVariantId(_)
228228
| ModuleDefId::ModuleId(_)
229229
| ModuleDefId::MacroId(_)

crates/hir/src/attrs.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use hir_ty::db::HirDatabase;
1212
use syntax::{ast, AstNode};
1313

1414
use crate::{
15-
Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam,
16-
Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias, TypeParam, Union,
17-
Variant,
15+
Adt, AssocItem, Const, ConstParam, Enum, ExternCrateDecl, Field, Function, GenericParam, Impl,
16+
LifetimeParam, Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias,
17+
TypeParam, Union, Variant,
1818
};
1919

2020
pub trait HasAttrs {
@@ -120,6 +120,39 @@ impl HasAttrs for AssocItem {
120120
}
121121
}
122122

123+
impl HasAttrs for ExternCrateDecl {
124+
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
125+
let def = AttrDefId::ExternCrateId(self.into());
126+
db.attrs_with_owner(def)
127+
}
128+
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
129+
let crate_docs = self.resolved_crate(db)?.root_module().attrs(db).docs().map(String::from);
130+
let def = AttrDefId::ExternCrateId(self.into());
131+
let decl_docs = db.attrs(def).docs().map(String::from);
132+
match (decl_docs, crate_docs) {
133+
(None, None) => None,
134+
(Some(decl_docs), None) => Some(decl_docs),
135+
(None, Some(crate_docs)) => Some(crate_docs),
136+
(Some(mut decl_docs), Some(crate_docs)) => {
137+
decl_docs.push('\n');
138+
decl_docs.push('\n');
139+
decl_docs += &crate_docs;
140+
Some(decl_docs)
141+
}
142+
}
143+
.map(Documentation::new)
144+
}
145+
fn resolve_doc_path(
146+
self,
147+
db: &dyn HirDatabase,
148+
link: &str,
149+
ns: Option<Namespace>,
150+
) -> Option<ModuleDef> {
151+
let def = AttrDefId::ExternCrateId(self.into());
152+
resolve_doc_path(db, def, link, ns).map(ModuleDef::from)
153+
}
154+
}
155+
123156
/// Resolves the item `link` points to in the scope of `def`.
124157
fn resolve_doc_path(
125158
db: &dyn HirDatabase,

crates/hir/src/db.rs

-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,3 @@ pub use hir_expand::db::{
1010
MacroExpandQuery, ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery,
1111
};
1212
pub use hir_ty::db::*;
13-
14-
#[test]
15-
fn hir_database_is_object_safe() {
16-
fn _assert_object_safe(_: &dyn HirDatabase) {}
17-
}

crates/hir/src/display.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use hir_ty::{
1818
};
1919

2020
use crate::{
21-
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, Field, Function, GenericParam,
22-
HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, Trait, TraitAlias,
23-
TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
21+
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, Field,
22+
Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct,
23+
Trait, TraitAlias, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
2424
};
2525

2626
impl HirDisplay for Function {
@@ -238,6 +238,18 @@ impl HirDisplay for Type {
238238
}
239239
}
240240

241+
impl HirDisplay for ExternCrateDecl {
242+
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
243+
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
244+
f.write_str("extern crate ")?;
245+
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
246+
if let Some(alias) = self.alias(f.db) {
247+
write!(f, " as {alias}",)?;
248+
}
249+
Ok(())
250+
}
251+
}
252+
241253
impl HirDisplay for GenericParam {
242254
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
243255
match self {

crates/hir/src/from_id.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
};
1616

1717
macro_rules! from_id {
18-
($(($id:path, $ty:path)),*) => {$(
18+
($(($id:path, $ty:path)),* $(,)?) => {$(
1919
impl From<$id> for $ty {
2020
fn from(id: $id) -> $ty {
2121
$ty { id }
@@ -47,7 +47,8 @@ from_id![
4747
(hir_def::TypeParamId, crate::TypeParam),
4848
(hir_def::ConstParamId, crate::ConstParam),
4949
(hir_def::LifetimeParamId, crate::LifetimeParam),
50-
(hir_def::MacroId, crate::Macro)
50+
(hir_def::MacroId, crate::Macro),
51+
(hir_def::ExternCrateId, crate::ExternCrateDecl),
5152
];
5253

5354
impl From<AdtId> for Adt {

crates/hir/src/has_source.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ use hir_expand::{HirFileId, InFile};
1111
use syntax::ast;
1212

1313
use crate::{
14-
db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
15-
LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam,
16-
Union, Variant,
14+
db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
15+
LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias,
16+
TypeOrConstParam, Union, Variant,
1717
};
1818

1919
pub trait HasSource {
@@ -207,3 +207,11 @@ impl HasSource for LocalSource {
207207
Some(self.source)
208208
}
209209
}
210+
211+
impl HasSource for ExternCrateDecl {
212+
type Ast = ast::ExternCrate;
213+
214+
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
215+
Some(self.id.lookup(db.upcast()).source(db.upcast()))
216+
}
217+
}

crates/hir/src/lib.rs

+56-9
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ use hir_def::{
4848
layout::{self, ReprOptions, TargetDataLayout},
4949
macro_id_to_def_id,
5050
nameres::{self, diagnostics::DefDiagnostic},
51+
path::ImportAlias,
5152
per_ns::PerNs,
5253
resolver::{HasResolver, Resolver},
5354
src::HasSource as _,
54-
AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
55-
EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId,
56-
LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId,
57-
StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId,
58-
UnionId,
55+
AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId,
56+
EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, HasModule, ImplId,
57+
InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup,
58+
MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
59+
TypeOrConstParamId, TypeParamId, UnionId,
5960
};
6061
use hir_expand::{name::name, MacroCallKind};
6162
use hir_ty::{
@@ -200,9 +201,8 @@ impl Crate {
200201
db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id })
201202
}
202203

203-
pub fn root_module(self, db: &dyn HirDatabase) -> Module {
204-
let def_map = db.crate_def_map(self.id);
205-
Module { id: def_map.crate_root().into() }
204+
pub fn root_module(self) -> Module {
205+
Module { id: CrateRootModuleId::from(self.id).into() }
206206
}
207207

208208
pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
@@ -247,7 +247,7 @@ impl Crate {
247247
/// Try to get the root URL of the documentation of a crate.
248248
pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
249249
// Look for #![doc(html_root_url = "...")]
250-
let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
250+
let attrs = db.attrs(AttrDefId::ModuleId(self.root_module().into()));
251251
let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
252252
doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
253253
}
@@ -2128,6 +2128,47 @@ impl HasVisibility for Function {
21282128
}
21292129
}
21302130

2131+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2132+
pub struct ExternCrateDecl {
2133+
pub(crate) id: ExternCrateId,
2134+
}
2135+
2136+
impl ExternCrateDecl {
2137+
pub fn module(self, db: &dyn HirDatabase) -> Module {
2138+
self.id.module(db.upcast()).into()
2139+
}
2140+
2141+
pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> {
2142+
db.extern_crate_decl_data(self.id).crate_id.map(Into::into)
2143+
}
2144+
2145+
pub fn name(self, db: &dyn HirDatabase) -> Name {
2146+
db.extern_crate_decl_data(self.id).name.clone()
2147+
}
2148+
2149+
pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> {
2150+
db.extern_crate_decl_data(self.id).alias.clone()
2151+
}
2152+
2153+
/// Returns the name under which this crate is made accessible, taking `_` into account.
2154+
pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> {
2155+
let extern_crate_decl_data = db.extern_crate_decl_data(self.id);
2156+
match &extern_crate_decl_data.alias {
2157+
Some(ImportAlias::Underscore) => None,
2158+
Some(ImportAlias::Alias(alias)) => Some(alias.clone()),
2159+
None => Some(extern_crate_decl_data.name.clone()),
2160+
}
2161+
}
2162+
}
2163+
2164+
impl HasVisibility for ExternCrateDecl {
2165+
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
2166+
db.extern_crate_decl_data(self.id)
2167+
.visibility
2168+
.resolve(db.upcast(), &self.id.resolver(db.upcast()))
2169+
}
2170+
}
2171+
21312172
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21322173
pub struct InTypeConst {
21332174
pub(crate) id: InTypeConstId,
@@ -4715,6 +4756,12 @@ pub trait HasContainer {
47154756
fn container(&self, db: &dyn HirDatabase) -> ItemContainer;
47164757
}
47174758

4759+
impl HasContainer for ExternCrateDecl {
4760+
fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
4761+
container_id_to_hir(self.id.lookup(db.upcast()).container.into())
4762+
}
4763+
}
4764+
47184765
impl HasContainer for Module {
47194766
fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
47204767
// FIXME: handle block expressions as modules (their parent is in a different DefMap)

0 commit comments

Comments
 (0)