Skip to content

Commit

Permalink
Auto merge of #16606 - Veykril:hover-extern, r=Veykril
Browse files Browse the repository at this point in the history
internal: Render assoc item owner in hover for items other than functions

Closes rust-lang/rust-analyzer#16603
  • Loading branch information
bors committed Feb 20, 2024
2 parents 26a16c4 + 85203d9 commit c888724
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 63 deletions.
88 changes: 88 additions & 0 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2653,6 +2653,37 @@ impl ItemInNs {
}
}

/// Invariant: `inner.as_extern_assoc_item(db).is_some()`
/// We do not actively enforce this invariant.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ExternAssocItem {
Function(Function),
Static(Static),
TypeAlias(TypeAlias),
}

pub trait AsExternAssocItem {
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem>;
}

impl AsExternAssocItem for Function {
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
as_extern_assoc_item(db, ExternAssocItem::Function, self.id)
}
}

impl AsExternAssocItem for Static {
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
as_extern_assoc_item(db, ExternAssocItem::Static, self.id)
}
}

impl AsExternAssocItem for TypeAlias {
fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
as_extern_assoc_item(db, ExternAssocItem::TypeAlias, self.id)
}
}

/// Invariant: `inner.as_assoc_item(db).is_some()`
/// We do not actively enforce this invariant.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -2727,6 +2758,63 @@ where
}
}

fn as_extern_assoc_item<'db, ID, DEF, LOC>(
db: &(dyn HirDatabase + 'db),
ctor: impl FnOnce(DEF) -> ExternAssocItem,
id: ID,
) -> Option<ExternAssocItem>
where
ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<LOC>>,
DEF: From<ID>,
LOC: ItemTreeNode,
{
match id.lookup(db.upcast()).container {
ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))),
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) | ItemContainerId::ModuleId(_) => {
None
}
}
}

impl ExternAssocItem {
pub fn name(self, db: &dyn HirDatabase) -> Name {
match self {
Self::Function(it) => it.name(db),
Self::Static(it) => it.name(db),
Self::TypeAlias(it) => it.name(db),
}
}

pub fn module(self, db: &dyn HirDatabase) -> Module {
match self {
Self::Function(f) => f.module(db),
Self::Static(c) => c.module(db),
Self::TypeAlias(t) => t.module(db),
}
}

pub fn as_function(self) -> Option<Function> {
match self {
Self::Function(v) => Some(v),
_ => None,
}
}

pub fn as_static(self) -> Option<Static> {
match self {
Self::Static(v) => Some(v),
_ => None,
}
}

pub fn as_type_alias(self) -> Option<TypeAlias> {
match self {
Self::TypeAlias(v) => Some(v),
_ => None,
}
}
}

impl AssocItem {
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
match self {
Expand Down
34 changes: 24 additions & 10 deletions crates/ide-db/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
use arrayvec::ArrayVec;
use either::Either;
use hir::{
Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate,
DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam,
HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution,
Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef,
Visibility,
Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module,
ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField,
TypeAlias, Variant, VariantDef, Visibility,
};
use stdx::{format_to, impl_from};
use syntax::{
Expand Down Expand Up @@ -213,8 +213,8 @@ impl Definition {
})
}

pub fn label(&self, db: &RootDatabase) -> Option<String> {
let label = match *self {
pub fn label(&self, db: &RootDatabase) -> String {
match *self {
Definition::Macro(it) => it.display(db).to_string(),
Definition::Field(it) => it.display(db).to_string(),
Definition::TupleField(it) => it.display(db).to_string(),
Expand All @@ -241,16 +241,19 @@ impl Definition {
}
}
Definition::SelfType(impl_def) => {
impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))?
let self_ty = &impl_def.self_ty(db);
match self_ty.as_adt() {
Some(it) => it.display(db).to_string(),
None => self_ty.display(db).to_string(),
}
}
Definition::GenericParam(it) => it.display(db).to_string(),
Definition::Label(it) => it.name(db).display(db).to_string(),
Definition::ExternCrateDecl(it) => it.display(db).to_string(),
Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)),
Definition::ToolModule(it) => it.name(db).to_string(),
Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)),
};
Some(label)
}
}
}

Expand Down Expand Up @@ -739,6 +742,17 @@ impl AsAssocItem for Definition {
}
}

impl AsExternAssocItem for Definition {
fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<ExternAssocItem> {
match self {
Definition::Function(it) => it.as_extern_assoc_item(db),
Definition::Static(it) => it.as_extern_assoc_item(db),
Definition::TypeAlias(it) => it.as_extern_assoc_item(db),
_ => None,
}
}
}

impl From<AssocItem> for Definition {
fn from(assoc_item: AssocItem) -> Self {
match assoc_item {
Expand Down
37 changes: 18 additions & 19 deletions crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fn hover_simple(
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
cov_mark::hit!(no_highlight_on_comment_hover);
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
let res = hover_for_definition(sema, file_id, def, &node, config)?;
let res = hover_for_definition(sema, file_id, def, &node, config);
Some(RangeInfo::new(range, res))
});
}
Expand All @@ -161,7 +161,7 @@ fn hover_simple(
Definition::from(resolution?),
&original_token.parent()?,
config,
)?;
);
return Some(RangeInfo::new(range, res));
}

Expand Down Expand Up @@ -215,7 +215,7 @@ fn hover_simple(
})
.flatten()
.unique_by(|&(def, _)| def)
.filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
.map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
acc.actions.extend(actions);
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
Expand Down Expand Up @@ -373,9 +373,9 @@ pub(crate) fn hover_for_definition(
def: Definition,
scope_node: &SyntaxNode,
config: &HoverConfig,
) -> Option<HoverResult> {
) -> HoverResult {
let famous_defs = match &def {
Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())),
Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())),
_ => None,
};

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

render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config).map(|markup| {
HoverResult {
markup: render::process_markup(sema.db, def, &markup, config),
actions: [
show_implementations_action(sema.db, def),
show_fn_references_action(sema.db, def),
runnable_action(sema, def, file_id),
goto_type_action_for_def(sema.db, def, &notable_traits),
]
.into_iter()
.flatten()
.collect(),
}
})
let markup = render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config);
HoverResult {
markup: render::process_markup(sema.db, def, &markup, config),
actions: [
show_implementations_action(sema.db, def),
show_fn_references_action(sema.db, def),
runnable_action(sema, def, file_id),
goto_type_action_for_def(sema.db, def, &notable_traits),
]
.into_iter()
.flatten()
.collect(),
}
}

fn notable_traits(
Expand Down
36 changes: 22 additions & 14 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::{mem, ops::Not};

use either::Either;
use hir::{
Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name,
Semantics, Trait, Type, TypeInfo,
Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout,
LayoutError, Name, Semantics, Trait, Type, TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
Expand Down Expand Up @@ -264,7 +264,7 @@ pub(super) fn keyword(
let markup = process_markup(
sema.db,
Definition::Module(doc_owner),
&markup(Some(docs.into()), description, None)?,
&markup(Some(docs.into()), description, None),
config,
);
Some(HoverResult { markup, actions })
Expand Down Expand Up @@ -369,12 +369,20 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
match def {
Definition::Field(f) => Some(f.parent_def(db).name(db)),
Definition::Local(l) => l.parent(db).name(db),
Definition::Function(f) => match f.as_assoc_item(db)?.container(db) {
hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
},
Definition::Variant(e) => Some(e.parent_enum(db).name(db)),
_ => None,

d => {
if let Some(assoc_item) = d.as_assoc_item(db) {
match assoc_item.container(db) {
hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
hir::AssocItemContainer::Impl(i) => {
i.self_ty(db).as_adt().map(|adt| adt.name(db))
}
}
} else {
return d.as_extern_assoc_item(db).map(|_| "<extern>".to_owned());
}
}
}
.map(|name| name.display(db).to_string())
}
Expand All @@ -396,11 +404,11 @@ pub(super) fn definition(
famous_defs: Option<&FamousDefs<'_, '_>>,
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
config: &HoverConfig,
) -> Option<Markup> {
) -> Markup {
let mod_path = definition_mod_path(db, &def);
let label = def.label(db)?;
let label = def.label(db);
let docs = def.docs(db, famous_defs);
let value = match def {
let value = (|| match def {
Definition::Variant(it) => {
if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
Expand Down Expand Up @@ -436,7 +444,7 @@ pub(super) fn definition(
Some(body.to_string())
}
_ => None,
};
})();

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

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

if let Some(mod_path) = mod_path {
Expand All @@ -696,7 +704,7 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Optio
if let Some(doc) = docs {
format_to!(buf, "\n___\n\n{}", doc);
}
Some(buf.into())
buf.into()
}

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

0 comments on commit c888724

Please sign in to comment.