Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/hover/render.rs')
-rw-r--r--crates/ide/src/hover/render.rs226
1 files changed, 145 insertions, 81 deletions
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 96a97ab44c..1362146413 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -3,8 +3,8 @@ use std::fmt::Display;
use either::Either;
use hir::{
- Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasCrate, HasSource, HirDisplay,
- Layout, Semantics, TypeInfo,
+ Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasSource, HirDisplay, Layout,
+ LayoutError, Semantics, TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
@@ -27,7 +27,8 @@ use syntax::{
use crate::{
doc_links::{remove_links, rewrite_links},
hover::walk_and_push_ty,
- HoverAction, HoverConfig, HoverResult, Markup,
+ HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig,
+ MemoryLayoutHoverRenderKind,
};
pub(super) fn type_info_of(
@@ -393,32 +394,27 @@ pub(super) fn definition(
let mod_path = definition_mod_path(db, &def);
let (label, docs) = match def {
Definition::Macro(it) => label_and_docs(db, it),
- Definition::Field(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
- let var_def = it.parent_def(db);
- let id = it.index();
- let layout = it.layout(db).ok()?;
- let offset = match var_def {
- hir::VariantDef::Struct(s) => Adt::from(s)
- .layout(db)
- .ok()
- .and_then(|layout| Some(format!(", offset = {:#X}", layout.field_offset(id)?))),
- _ => None,
- };
- let niches = niches(db, it, &layout).unwrap_or_default();
- Some(format!(
- "size = {:#X}, align = {:#X}{}{niches}",
- layout.size(),
- layout.align(),
- offset.as_deref().unwrap_or_default()
- ))
- }),
+ Definition::Field(it) => label_and_layout_info_and_docs(
+ db,
+ it,
+ config,
+ |&it| it.layout(db),
+ |_| {
+ let var_def = it.parent_def(db);
+ let id = it.index();
+ match var_def {
+ hir::VariantDef::Struct(s) => {
+ Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(id))
+ }
+ _ => None,
+ }
+ },
+ ),
Definition::Module(it) => label_and_docs(db, it),
Definition::Function(it) => label_and_docs(db, it),
- Definition::Adt(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
- let layout = it.layout(db).ok()?;
- let niches = niches(db, it, &layout).unwrap_or_default();
- Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align()))
- }),
+ Definition::Adt(it) => {
+ label_and_layout_info_and_docs(db, it, config, |&it| it.layout(db), |_| None)
+ }
Definition::Variant(it) => label_value_and_layout_info_and_docs(
db,
it,
@@ -435,16 +431,8 @@ pub(super) fn definition(
None
}
},
- |&it| {
- let (layout, tag_size) = it.layout(db).ok()?;
- let size = layout.size() as usize - tag_size;
- if size == 0 {
- // There is no value in showing layout info for fieldless variants
- return None;
- }
- let niches = niches(db, it, &layout).unwrap_or_default();
- Some(format!("size = {:#X}{niches}", layout.size()))
- },
+ |it| it.layout(db),
+ |layout| layout.enum_tag_size(),
),
Definition::Const(it) => label_value_and_docs(db, it, |it| {
let body = it.render_eval(db);
@@ -470,11 +458,9 @@ pub(super) fn definition(
}),
Definition::Trait(it) => label_and_docs(db, it),
Definition::TraitAlias(it) => label_and_docs(db, it),
- Definition::TypeAlias(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
- let layout = it.ty(db).layout(db).ok()?;
- let niches = niches(db, it, &layout).unwrap_or_default();
- Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align(),))
- }),
+ Definition::TypeAlias(it) => {
+ label_and_layout_info_and_docs(db, it, config, |&it| it.ty(db).layout(db), |_| None)
+ }
Definition::BuiltinType(it) => {
return famous_defs
.and_then(|fd| builtin(fd, it))
@@ -509,10 +495,6 @@ pub(super) fn definition(
markup(docs, label, mod_path)
}
-fn niches(db: &RootDatabase, it: impl HasCrate, layout: &Layout) -> Option<String> {
- Some(format!(", niches = {}", layout.niches(db, it.krate(db).into())?))
-}
-
fn type_info(
sema: &Semantics<'_, RootDatabase>,
config: &HoverConfig,
@@ -557,14 +539,6 @@ fn closure_ty(
TypeInfo { original, adjusted }: &TypeInfo,
) -> Option<HoverResult> {
let c = original.as_closure()?;
- let layout = if config.memory_layout {
- original
- .layout(sema.db)
- .map(|x| format!(" // size = {}, align = {}", x.size(), x.align()))
- .unwrap_or_default()
- } else {
- String::default()
- };
let mut captures_rendered = c.captured_items(sema.db)
.into_iter()
.map(|it| {
@@ -600,17 +574,23 @@ fn closure_ty(
} else {
String::new()
};
+ let mut markup = format!("```rust\n{}", c.display_with_id(sema.db),);
- let mut res = HoverResult::default();
- res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
- res.markup = format!(
- "```rust\n{}{}\n{}\n```{adjusted}\n\n## Captures\n{}",
- c.display_with_id(sema.db),
- layout,
+ if let Some(layout) =
+ render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None)
+ {
+ format_to!(markup, "{layout}");
+ }
+ format_to!(
+ markup,
+ "\n{}\n```{adjusted}\n\n## Captures\n{}",
c.display_with_impl(sema.db),
captures_rendered,
- )
- .into();
+ );
+
+ let mut res = HoverResult::default();
+ res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
+ res.markup = markup.into();
Some(res)
}
@@ -644,48 +624,59 @@ where
(label, docs)
}
-fn label_and_layout_info_and_docs<D, E, V>(
+fn label_and_layout_info_and_docs<D, E, E2>(
db: &RootDatabase,
def: D,
config: &HoverConfig,
layout_extractor: E,
+ layout_offset_extractor: E2,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
- E: Fn(&D) -> Option<V>,
- V: Display,
+ E: Fn(&D) -> Result<Layout, LayoutError>,
+ E2: Fn(&Layout) -> Option<u64>,
{
- let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
- Some(layout) => format!("{} // {layout}", def.display(db)),
- _ => def.display(db).to_string(),
- };
+ let mut label = def.display(db).to_string();
+ if let Some(layout) = render_memory_layout(
+ config.memory_layout,
+ || layout_extractor(&def),
+ layout_offset_extractor,
+ |_| None,
+ ) {
+ format_to!(label, "{layout}");
+ }
let docs = def.attrs(db).docs();
(label, docs)
}
-fn label_value_and_layout_info_and_docs<D, E, E2, V, L>(
+fn label_value_and_layout_info_and_docs<D, E, E2, E3, V>(
db: &RootDatabase,
def: D,
config: &HoverConfig,
value_extractor: E,
layout_extractor: E2,
+ layout_tag_extractor: E3,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
E: Fn(&D) -> Option<V>,
- E2: Fn(&D) -> Option<L>,
+ E2: Fn(&D) -> Result<Layout, LayoutError>,
+ E3: Fn(&Layout) -> Option<usize>,
V: Display,
- L: Display,
{
let value = value_extractor(&def);
- let label = match value {
+ let mut label = match value {
Some(value) => format!("{} = {value}", def.display(db)),
None => def.display(db).to_string(),
};
- let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
- Some(layout) => format!("{} // {layout}", label),
- _ => label,
- };
+ if let Some(layout) = render_memory_layout(
+ config.memory_layout,
+ || layout_extractor(&def),
+ |_| None,
+ layout_tag_extractor,
+ ) {
+ format_to!(label, "{layout}");
+ }
let docs = def.attrs(db).docs();
(label, docs)
}
@@ -769,14 +760,87 @@ fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option<Mark
}
None => format!("{is_mut}self: {ty}"),
};
- if config.memory_layout {
- if let Ok(layout) = it.ty(db).layout(db) {
- format_to!(desc, " // size = {}, align = {}", layout.size(), layout.align());
- }
+ if let Some(layout) =
+ render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
+ {
+ format_to!(desc, "{layout}");
}
markup(None, desc, None)
}
+fn render_memory_layout(
+ config: Option<MemoryLayoutHoverConfig>,
+ layout: impl FnOnce() -> Result<Layout, LayoutError>,
+ offset: impl FnOnce(&Layout) -> Option<u64>,
+ tag: impl FnOnce(&Layout) -> Option<usize>,
+) -> Option<String> {
+ // field
+
+ let config = config?;
+ let layout = layout().ok()?;
+
+ let mut label = String::from(" // ");
+
+ if let Some(render) = config.size {
+ let size = match tag(&layout) {
+ Some(tag) => layout.size() as usize - tag,
+ None => layout.size() as usize,
+ };
+ format_to!(label, "size = ");
+ match render {
+ MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{size}"),
+ MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{size:#X}"),
+ MemoryLayoutHoverRenderKind::Both if size >= 10 => {
+ format_to!(label, "{size} ({size:#X})")
+ }
+ MemoryLayoutHoverRenderKind::Both => format_to!(label, "{size}"),
+ }
+ format_to!(label, ", ");
+ }
+
+ if let Some(render) = config.alignment {
+ let align = layout.align();
+ format_to!(label, "align = ");
+ match render {
+ MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{align}",),
+ MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{align:#X}",),
+ MemoryLayoutHoverRenderKind::Both if align >= 10 => {
+ format_to!(label, "{align} ({align:#X})")
+ }
+ MemoryLayoutHoverRenderKind::Both => {
+ format_to!(label, "{align}")
+ }
+ }
+ format_to!(label, ", ");
+ }
+
+ if let Some(render) = config.offset {
+ if let Some(offset) = offset(&layout) {
+ format_to!(label, "offset = ");
+ match render {
+ MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{offset}"),
+ MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{offset:#X}"),
+ MemoryLayoutHoverRenderKind::Both if offset >= 10 => {
+ format_to!(label, "{offset} ({offset:#X})")
+ }
+ MemoryLayoutHoverRenderKind::Both => {
+ format_to!(label, "{offset}")
+ }
+ }
+ format_to!(label, ", ");
+ }
+ }
+
+ if config.niches {
+ if let Some(niches) = layout.niches() {
+ format_to!(label, "niches = {niches}, ");
+ }
+ }
+ label.pop(); // ' '
+ label.pop(); // ','
+ Some(label)
+}
+
struct KeywordHint {
description: String,
keyword_mod: String,