Skip to content

Commit c888724

Browse files
committed
Auto merge of rust-lang#16606 - Veykril:hover-extern, r=Veykril
internal: Render assoc item owner in hover for items other than functions Closes rust-lang/rust-analyzer#16603
2 parents 26a16c4 + 85203d9 commit c888724

File tree

6 files changed

+267
-63
lines changed

6 files changed

+267
-63
lines changed

crates/hir/src/lib.rs

+88
Original file line numberDiff line numberDiff line change
@@ -2653,6 +2653,37 @@ impl ItemInNs {
26532653
}
26542654
}
26552655

2656+
/// Invariant: `inner.as_extern_assoc_item(db).is_some()`
2657+
/// We do not actively enforce this invariant.
2658+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2659+
pub enum ExternAssocItem {
2660+
Function(Function),
2661+
Static(Static),
2662+
TypeAlias(TypeAlias),
2663+
}
2664+
2665+
pub trait AsExternAssocItem {
2666+
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem>;
2667+
}
2668+
2669+
impl AsExternAssocItem for Function {
2670+
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
2671+
as_extern_assoc_item(db, ExternAssocItem::Function, self.id)
2672+
}
2673+
}
2674+
2675+
impl AsExternAssocItem for Static {
2676+
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
2677+
as_extern_assoc_item(db, ExternAssocItem::Static, self.id)
2678+
}
2679+
}
2680+
2681+
impl AsExternAssocItem for TypeAlias {
2682+
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
2683+
as_extern_assoc_item(db, ExternAssocItem::TypeAlias, self.id)
2684+
}
2685+
}
2686+
26562687
/// Invariant: `inner.as_assoc_item(db).is_some()`
26572688
/// We do not actively enforce this invariant.
26582689
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -2727,6 +2758,63 @@ where
27272758
}
27282759
}
27292760

2761+
fn as_extern_assoc_item<'db, ID, DEF, LOC>(
2762+
db: &(dyn HirDatabase + 'db),
2763+
ctor: impl FnOnce(DEF) -> ExternAssocItem,
2764+
id: ID,
2765+
) -> Option<ExternAssocItem>
2766+
where
2767+
ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<LOC>>,
2768+
DEF: From<ID>,
2769+
LOC: ItemTreeNode,
2770+
{
2771+
match id.lookup(db.upcast()).container {
2772+
ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))),
2773+
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) | ItemContainerId::ModuleId(_) => {
2774+
None
2775+
}
2776+
}
2777+
}
2778+
2779+
impl ExternAssocItem {
2780+
pub fn name(self, db: &dyn HirDatabase) -> Name {
2781+
match self {
2782+
Self::Function(it) => it.name(db),
2783+
Self::Static(it) => it.name(db),
2784+
Self::TypeAlias(it) => it.name(db),
2785+
}
2786+
}
2787+
2788+
pub fn module(self, db: &dyn HirDatabase) -> Module {
2789+
match self {
2790+
Self::Function(f) => f.module(db),
2791+
Self::Static(c) => c.module(db),
2792+
Self::TypeAlias(t) => t.module(db),
2793+
}
2794+
}
2795+
2796+
pub fn as_function(self) -> Option<Function> {
2797+
match self {
2798+
Self::Function(v) => Some(v),
2799+
_ => None,
2800+
}
2801+
}
2802+
2803+
pub fn as_static(self) -> Option<Static> {
2804+
match self {
2805+
Self::Static(v) => Some(v),
2806+
_ => None,
2807+
}
2808+
}
2809+
2810+
pub fn as_type_alias(self) -> Option<TypeAlias> {
2811+
match self {
2812+
Self::TypeAlias(v) => Some(v),
2813+
_ => None,
2814+
}
2815+
}
2816+
}
2817+
27302818
impl AssocItem {
27312819
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
27322820
match self {

crates/ide-db/src/defs.rs

+24-10
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
use arrayvec::ArrayVec;
99
use either::Either;
1010
use hir::{
11-
Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate,
12-
DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam,
13-
HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution,
14-
Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef,
15-
Visibility,
11+
Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
12+
Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
13+
Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module,
14+
ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField,
15+
TypeAlias, Variant, VariantDef, Visibility,
1616
};
1717
use stdx::{format_to, impl_from};
1818
use syntax::{
@@ -213,8 +213,8 @@ impl Definition {
213213
})
214214
}
215215

216-
pub fn label(&self, db: &RootDatabase) -> Option<String> {
217-
let label = match *self {
216+
pub fn label(&self, db: &RootDatabase) -> String {
217+
match *self {
218218
Definition::Macro(it) => it.display(db).to_string(),
219219
Definition::Field(it) => it.display(db).to_string(),
220220
Definition::TupleField(it) => it.display(db).to_string(),
@@ -241,16 +241,19 @@ impl Definition {
241241
}
242242
}
243243
Definition::SelfType(impl_def) => {
244-
impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))?
244+
let self_ty = &impl_def.self_ty(db);
245+
match self_ty.as_adt() {
246+
Some(it) => it.display(db).to_string(),
247+
None => self_ty.display(db).to_string(),
248+
}
245249
}
246250
Definition::GenericParam(it) => it.display(db).to_string(),
247251
Definition::Label(it) => it.name(db).display(db).to_string(),
248252
Definition::ExternCrateDecl(it) => it.display(db).to_string(),
249253
Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)),
250254
Definition::ToolModule(it) => it.name(db).to_string(),
251255
Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)),
252-
};
253-
Some(label)
256+
}
254257
}
255258
}
256259

@@ -739,6 +742,17 @@ impl AsAssocItem for Definition {
739742
}
740743
}
741744

745+
impl AsExternAssocItem for Definition {
746+
fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<ExternAssocItem> {
747+
match self {
748+
Definition::Function(it) => it.as_extern_assoc_item(db),
749+
Definition::Static(it) => it.as_extern_assoc_item(db),
750+
Definition::TypeAlias(it) => it.as_extern_assoc_item(db),
751+
_ => None,
752+
}
753+
}
754+
}
755+
742756
impl From<AssocItem> for Definition {
743757
fn from(assoc_item: AssocItem) -> Self {
744758
match assoc_item {

crates/ide/src/hover.rs

+18-19
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ fn hover_simple(
147147
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
148148
cov_mark::hit!(no_highlight_on_comment_hover);
149149
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
150-
let res = hover_for_definition(sema, file_id, def, &node, config)?;
150+
let res = hover_for_definition(sema, file_id, def, &node, config);
151151
Some(RangeInfo::new(range, res))
152152
});
153153
}
@@ -161,7 +161,7 @@ fn hover_simple(
161161
Definition::from(resolution?),
162162
&original_token.parent()?,
163163
config,
164-
)?;
164+
);
165165
return Some(RangeInfo::new(range, res));
166166
}
167167

@@ -215,7 +215,7 @@ fn hover_simple(
215215
})
216216
.flatten()
217217
.unique_by(|&(def, _)| def)
218-
.filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
218+
.map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
219219
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
220220
acc.actions.extend(actions);
221221
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
@@ -373,9 +373,9 @@ pub(crate) fn hover_for_definition(
373373
def: Definition,
374374
scope_node: &SyntaxNode,
375375
config: &HoverConfig,
376-
) -> Option<HoverResult> {
376+
) -> HoverResult {
377377
let famous_defs = match &def {
378-
Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())),
378+
Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())),
379379
_ => None,
380380
};
381381

@@ -396,20 +396,19 @@ pub(crate) fn hover_for_definition(
396396
};
397397
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
398398

399-
render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config).map(|markup| {
400-
HoverResult {
401-
markup: render::process_markup(sema.db, def, &markup, config),
402-
actions: [
403-
show_implementations_action(sema.db, def),
404-
show_fn_references_action(sema.db, def),
405-
runnable_action(sema, def, file_id),
406-
goto_type_action_for_def(sema.db, def, &notable_traits),
407-
]
408-
.into_iter()
409-
.flatten()
410-
.collect(),
411-
}
412-
})
399+
let markup = render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config);
400+
HoverResult {
401+
markup: render::process_markup(sema.db, def, &markup, config),
402+
actions: [
403+
show_implementations_action(sema.db, def),
404+
show_fn_references_action(sema.db, def),
405+
runnable_action(sema, def, file_id),
406+
goto_type_action_for_def(sema.db, def, &notable_traits),
407+
]
408+
.into_iter()
409+
.flatten()
410+
.collect(),
411+
}
413412
}
414413

415414
fn notable_traits(

crates/ide/src/hover/render.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::{mem, ops::Not};
33

44
use either::Either;
55
use hir::{
6-
Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name,
7-
Semantics, Trait, Type, TypeInfo,
6+
Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout,
7+
LayoutError, Name, Semantics, Trait, Type, TypeInfo,
88
};
99
use ide_db::{
1010
base_db::SourceDatabase,
@@ -264,7 +264,7 @@ pub(super) fn keyword(
264264
let markup = process_markup(
265265
sema.db,
266266
Definition::Module(doc_owner),
267-
&markup(Some(docs.into()), description, None)?,
267+
&markup(Some(docs.into()), description, None),
268268
config,
269269
);
270270
Some(HoverResult { markup, actions })
@@ -369,12 +369,20 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
369369
match def {
370370
Definition::Field(f) => Some(f.parent_def(db).name(db)),
371371
Definition::Local(l) => l.parent(db).name(db),
372-
Definition::Function(f) => match f.as_assoc_item(db)?.container(db) {
373-
hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
374-
hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
375-
},
376372
Definition::Variant(e) => Some(e.parent_enum(db).name(db)),
377-
_ => None,
373+
374+
d => {
375+
if let Some(assoc_item) = d.as_assoc_item(db) {
376+
match assoc_item.container(db) {
377+
hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
378+
hir::AssocItemContainer::Impl(i) => {
379+
i.self_ty(db).as_adt().map(|adt| adt.name(db))
380+
}
381+
}
382+
} else {
383+
return d.as_extern_assoc_item(db).map(|_| "<extern>".to_owned());
384+
}
385+
}
378386
}
379387
.map(|name| name.display(db).to_string())
380388
}
@@ -396,11 +404,11 @@ pub(super) fn definition(
396404
famous_defs: Option<&FamousDefs<'_, '_>>,
397405
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
398406
config: &HoverConfig,
399-
) -> Option<Markup> {
407+
) -> Markup {
400408
let mod_path = definition_mod_path(db, &def);
401-
let label = def.label(db)?;
409+
let label = def.label(db);
402410
let docs = def.docs(db, famous_defs);
403-
let value = match def {
411+
let value = (|| match def {
404412
Definition::Variant(it) => {
405413
if !it.parent_enum(db).is_data_carrying(db) {
406414
match it.eval(db) {
@@ -436,7 +444,7 @@ pub(super) fn definition(
436444
Some(body.to_string())
437445
}
438446
_ => None,
439-
};
447+
})();
440448

441449
let layout_info = match def {
442450
Definition::Field(it) => render_memory_layout(
@@ -683,7 +691,7 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
683691
def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
684692
}
685693

686-
fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
694+
fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup {
687695
let mut buf = String::new();
688696

689697
if let Some(mod_path) = mod_path {
@@ -696,7 +704,7 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Optio
696704
if let Some(doc) = docs {
697705
format_to!(buf, "\n___\n\n{}", doc);
698706
}
699-
Some(buf.into())
707+
buf.into()
700708
}
701709

702710
fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {

0 commit comments

Comments
 (0)