mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Add render configs for memory layout hovers
This commit is contained in:
parent
76d86502f7
commit
3c862507b9
12 changed files with 400 additions and 163 deletions
|
@ -45,7 +45,7 @@ use hir_def::{
|
||||||
hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
|
hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
|
||||||
item_tree::ItemTreeNode,
|
item_tree::ItemTreeNode,
|
||||||
lang_item::LangItemTarget,
|
lang_item::LangItemTarget,
|
||||||
layout::{self, ReprOptions},
|
layout::{self, ReprOptions, TargetDataLayout},
|
||||||
macro_id_to_def_id,
|
macro_id_to_def_id,
|
||||||
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
|
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
|
@ -62,7 +62,7 @@ use hir_ty::{
|
||||||
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
|
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
|
||||||
diagnostics::BodyValidationDiagnostic,
|
diagnostics::BodyValidationDiagnostic,
|
||||||
display::HexifiedConst,
|
display::HexifiedConst,
|
||||||
layout::{Layout as TyLayout, LayoutError, RustcEnumVariantIdx, TagEncoding},
|
layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding},
|
||||||
method_resolution::{self, TyFingerprint},
|
method_resolution::{self, TyFingerprint},
|
||||||
mir::{self, interpret_mir},
|
mir::{self, interpret_mir},
|
||||||
primitive::UintTy,
|
primitive::UintTy,
|
||||||
|
@ -133,6 +133,7 @@ pub use {
|
||||||
},
|
},
|
||||||
hir_ty::{
|
hir_ty::{
|
||||||
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
|
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
|
||||||
|
layout::LayoutError,
|
||||||
mir::MirEvalError,
|
mir::MirEvalError,
|
||||||
PointerCast, Safety,
|
PointerCast, Safety,
|
||||||
},
|
},
|
||||||
|
@ -962,7 +963,8 @@ impl Field {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||||
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into()).map(Layout)
|
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into())
|
||||||
|
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
|
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
|
||||||
|
@ -1135,23 +1137,8 @@ impl Enum {
|
||||||
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
|
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout(self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
|
pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||||
let layout = Adt::from(self).layout(db)?;
|
Adt::from(self).layout(db)
|
||||||
let tag_size =
|
|
||||||
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.0.variants {
|
|
||||||
match tag_encoding {
|
|
||||||
TagEncoding::Direct => {
|
|
||||||
let target_data_layout = db
|
|
||||||
.target_data_layout(self.module(db).krate().id)
|
|
||||||
.ok_or(LayoutError::TargetLayoutNotAvailable)?;
|
|
||||||
tag.size(&*target_data_layout).bytes_usize()
|
|
||||||
}
|
|
||||||
TagEncoding::Niche { .. } => 0,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
Ok((layout, tag_size))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1214,19 +1201,16 @@ impl Variant {
|
||||||
db.const_eval_discriminant(self.into())
|
db.const_eval_discriminant(self.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return layout of the variant and tag size of the parent enum.
|
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
|
|
||||||
let parent_enum = self.parent_enum(db);
|
let parent_enum = self.parent_enum(db);
|
||||||
let (parent_layout, tag_size) = parent_enum.layout(db)?;
|
let parent_layout = parent_enum.layout(db)?;
|
||||||
Ok((
|
Ok(match &parent_layout.0.variants {
|
||||||
match &parent_layout.0.variants {
|
layout::Variants::Multiple { variants, .. } => Layout(
|
||||||
layout::Variants::Multiple { variants, .. } => {
|
Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()),
|
||||||
Layout(Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()))
|
db.target_data_layout(parent_enum.krate(db).into()).unwrap(),
|
||||||
}
|
),
|
||||||
_ => parent_layout,
|
_ => parent_layout,
|
||||||
},
|
})
|
||||||
tag_size,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1259,7 +1243,9 @@ impl Adt {
|
||||||
if db.generic_params(self.into()).iter().count() != 0 {
|
if db.generic_params(self.into()).iter().count() != 0 {
|
||||||
return Err(LayoutError::HasPlaceholder);
|
return Err(LayoutError::HasPlaceholder);
|
||||||
}
|
}
|
||||||
db.layout_of_adt(self.into(), Substitution::empty(Interner), self.krate(db).id).map(Layout)
|
let krate = self.krate(db).id;
|
||||||
|
db.layout_of_adt(self.into(), Substitution::empty(Interner), krate)
|
||||||
|
.map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turns this ADT into a type. Any type parameters of the ADT will be
|
/// Turns this ADT into a type. Any type parameters of the ADT will be
|
||||||
|
@ -4244,7 +4230,8 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||||
db.layout_of_ty(self.ty.clone(), self.env.krate).map(Layout)
|
db.layout_of_ty(self.ty.clone(), self.env.krate)
|
||||||
|
.map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4356,7 +4343,7 @@ fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::Closu
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Layout(Arc<TyLayout>);
|
pub struct Layout(Arc<TyLayout>, Arc<TargetDataLayout>);
|
||||||
|
|
||||||
impl Layout {
|
impl Layout {
|
||||||
pub fn size(&self) -> u64 {
|
pub fn size(&self) -> u64 {
|
||||||
|
@ -4367,8 +4354,8 @@ impl Layout {
|
||||||
self.0.align.abi.bytes()
|
self.0.align.abi.bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn niches(&self, db: &dyn HirDatabase, krate: Crate) -> Option<u128> {
|
pub fn niches(&self) -> Option<u128> {
|
||||||
Some(self.0.largest_niche?.available(&*db.target_data_layout(krate.id)?))
|
Some(self.0.largest_niche?.available(&*self.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn field_offset(&self, idx: usize) -> Option<u64> {
|
pub fn field_offset(&self, idx: usize) -> Option<u64> {
|
||||||
|
@ -4382,6 +4369,19 @@ impl Layout {
|
||||||
layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()),
|
layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enum_tag_size(&self) -> Option<usize> {
|
||||||
|
let tag_size =
|
||||||
|
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants {
|
||||||
|
match tag_encoding {
|
||||||
|
TagEncoding::Direct => tag.size(&*self.1).bytes_usize(),
|
||||||
|
TagEncoding::Niche { .. } => 0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(tag_size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
|
|
@ -55,7 +55,8 @@ pub(crate) fn convert_named_struct_to_tuple_struct(
|
||||||
// XXX: We don't currently provide this assist for struct definitions inside macros, but if we
|
// XXX: We don't currently provide this assist for struct definitions inside macros, but if we
|
||||||
// are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files
|
// are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files
|
||||||
// too.
|
// too.
|
||||||
let strukt = ctx.find_node_at_offset::<Either<ast::Struct, ast::Variant>>()?;
|
let name = ctx.find_node_at_offset::<ast::Name>()?;
|
||||||
|
let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
|
||||||
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
||||||
let record_fields = match field_list {
|
let record_fields = match field_list {
|
||||||
ast::FieldList::RecordFieldList(it) => it,
|
ast::FieldList::RecordFieldList(it) => it,
|
||||||
|
|
|
@ -50,7 +50,8 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
|
||||||
acc: &mut Assists,
|
acc: &mut Assists,
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let strukt = ctx.find_node_at_offset::<Either<ast::Struct, ast::Variant>>()?;
|
let name = ctx.find_node_at_offset::<ast::Name>()?;
|
||||||
|
let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
|
||||||
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
||||||
let tuple_fields = match field_list {
|
let tuple_fields = match field_list {
|
||||||
ast::FieldList::TupleFieldList(it) => it,
|
ast::FieldList::TupleFieldList(it) => it,
|
||||||
|
|
|
@ -273,8 +273,9 @@ fn assist_order_field_struct() {
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
|
assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
|
assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
|
assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Convert to tuple struct");
|
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
|
assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
|
||||||
|
assert_eq!(assists.next().expect("expected assist").label, "Generate `new`");
|
||||||
|
assert_eq!(assists.next().map(|it| it.label.to_string()), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -27,12 +27,27 @@ use crate::{
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct HoverConfig {
|
pub struct HoverConfig {
|
||||||
pub links_in_hover: bool,
|
pub links_in_hover: bool,
|
||||||
pub memory_layout: bool,
|
pub memory_layout: Option<MemoryLayoutHoverConfig>,
|
||||||
pub documentation: bool,
|
pub documentation: bool,
|
||||||
pub keywords: bool,
|
pub keywords: bool,
|
||||||
pub format: HoverDocFormat,
|
pub format: HoverDocFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct MemoryLayoutHoverConfig {
|
||||||
|
pub size: Option<MemoryLayoutHoverRenderKind>,
|
||||||
|
pub offset: Option<MemoryLayoutHoverRenderKind>,
|
||||||
|
pub alignment: Option<MemoryLayoutHoverRenderKind>,
|
||||||
|
pub niches: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum MemoryLayoutHoverRenderKind {
|
||||||
|
Decimal,
|
||||||
|
Hexadecimal,
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum HoverDocFormat {
|
pub enum HoverDocFormat {
|
||||||
Markdown,
|
Markdown,
|
||||||
|
|
|
@ -3,8 +3,8 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{
|
||||||
Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasCrate, HasSource, HirDisplay,
|
Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasSource, HirDisplay, Layout,
|
||||||
Layout, Semantics, TypeInfo,
|
LayoutError, Semantics, TypeInfo,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::SourceDatabase,
|
base_db::SourceDatabase,
|
||||||
|
@ -27,7 +27,8 @@ use syntax::{
|
||||||
use crate::{
|
use crate::{
|
||||||
doc_links::{remove_links, rewrite_links},
|
doc_links::{remove_links, rewrite_links},
|
||||||
hover::walk_and_push_ty,
|
hover::walk_and_push_ty,
|
||||||
HoverAction, HoverConfig, HoverResult, Markup,
|
HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig,
|
||||||
|
MemoryLayoutHoverRenderKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) fn type_info_of(
|
pub(super) fn type_info_of(
|
||||||
|
@ -393,32 +394,27 @@ pub(super) fn definition(
|
||||||
let mod_path = definition_mod_path(db, &def);
|
let mod_path = definition_mod_path(db, &def);
|
||||||
let (label, docs) = match def {
|
let (label, docs) = match def {
|
||||||
Definition::Macro(it) => label_and_docs(db, it),
|
Definition::Macro(it) => label_and_docs(db, it),
|
||||||
Definition::Field(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
|
Definition::Field(it) => label_and_layout_info_and_docs(
|
||||||
let var_def = it.parent_def(db);
|
db,
|
||||||
let id = it.index();
|
it,
|
||||||
let layout = it.layout(db).ok()?;
|
config,
|
||||||
let offset = match var_def {
|
|&it| it.layout(db),
|
||||||
hir::VariantDef::Struct(s) => Adt::from(s)
|
|_| {
|
||||||
.layout(db)
|
let var_def = it.parent_def(db);
|
||||||
.ok()
|
let id = it.index();
|
||||||
.and_then(|layout| Some(format!(", offset = {:#X}", layout.field_offset(id)?))),
|
match var_def {
|
||||||
_ => None,
|
hir::VariantDef::Struct(s) => {
|
||||||
};
|
Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(id))
|
||||||
let niches = niches(db, it, &layout).unwrap_or_default();
|
}
|
||||||
Some(format!(
|
_ => None,
|
||||||
"size = {:#X}, align = {:#X}{}{niches}",
|
}
|
||||||
layout.size(),
|
},
|
||||||
layout.align(),
|
),
|
||||||
offset.as_deref().unwrap_or_default()
|
|
||||||
))
|
|
||||||
}),
|
|
||||||
Definition::Module(it) => label_and_docs(db, it),
|
Definition::Module(it) => label_and_docs(db, it),
|
||||||
Definition::Function(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| {
|
Definition::Adt(it) => {
|
||||||
let layout = it.layout(db).ok()?;
|
label_and_layout_info_and_docs(db, it, config, |&it| it.layout(db), |_| None)
|
||||||
let niches = niches(db, it, &layout).unwrap_or_default();
|
}
|
||||||
Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align()))
|
|
||||||
}),
|
|
||||||
Definition::Variant(it) => label_value_and_layout_info_and_docs(
|
Definition::Variant(it) => label_value_and_layout_info_and_docs(
|
||||||
db,
|
db,
|
||||||
it,
|
it,
|
||||||
|
@ -435,16 +431,8 @@ pub(super) fn definition(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|&it| {
|
|it| it.layout(db),
|
||||||
let (layout, tag_size) = it.layout(db).ok()?;
|
|layout| layout.enum_tag_size(),
|
||||||
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()))
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
Definition::Const(it) => label_value_and_docs(db, it, |it| {
|
Definition::Const(it) => label_value_and_docs(db, it, |it| {
|
||||||
let body = it.render_eval(db);
|
let body = it.render_eval(db);
|
||||||
|
@ -470,11 +458,9 @@ pub(super) fn definition(
|
||||||
}),
|
}),
|
||||||
Definition::Trait(it) => label_and_docs(db, it),
|
Definition::Trait(it) => label_and_docs(db, it),
|
||||||
Definition::TraitAlias(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| {
|
Definition::TypeAlias(it) => {
|
||||||
let layout = it.ty(db).layout(db).ok()?;
|
label_and_layout_info_and_docs(db, it, config, |&it| it.ty(db).layout(db), |_| None)
|
||||||
let niches = niches(db, it, &layout).unwrap_or_default();
|
}
|
||||||
Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align(),))
|
|
||||||
}),
|
|
||||||
Definition::BuiltinType(it) => {
|
Definition::BuiltinType(it) => {
|
||||||
return famous_defs
|
return famous_defs
|
||||||
.and_then(|fd| builtin(fd, it))
|
.and_then(|fd| builtin(fd, it))
|
||||||
|
@ -509,10 +495,6 @@ pub(super) fn definition(
|
||||||
markup(docs, label, mod_path)
|
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(
|
fn type_info(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
config: &HoverConfig,
|
config: &HoverConfig,
|
||||||
|
@ -557,14 +539,6 @@ fn closure_ty(
|
||||||
TypeInfo { original, adjusted }: &TypeInfo,
|
TypeInfo { original, adjusted }: &TypeInfo,
|
||||||
) -> Option<HoverResult> {
|
) -> Option<HoverResult> {
|
||||||
let c = original.as_closure()?;
|
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)
|
let mut captures_rendered = c.captured_items(sema.db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|it| {
|
.map(|it| {
|
||||||
|
@ -600,17 +574,23 @@ fn closure_ty(
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
let mut markup = format!("```rust\n{}", c.display_with_id(sema.db),);
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
let mut res = HoverResult::default();
|
let mut res = HoverResult::default();
|
||||||
res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
|
res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
|
||||||
res.markup = format!(
|
res.markup = markup.into();
|
||||||
"```rust\n{}{}\n{}\n```{adjusted}\n\n## Captures\n{}",
|
|
||||||
c.display_with_id(sema.db),
|
|
||||||
layout,
|
|
||||||
c.display_with_impl(sema.db),
|
|
||||||
captures_rendered,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,48 +624,59 @@ where
|
||||||
(label, docs)
|
(label, docs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn label_and_layout_info_and_docs<D, E, V>(
|
fn label_and_layout_info_and_docs<D, E, E2>(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
def: D,
|
def: D,
|
||||||
config: &HoverConfig,
|
config: &HoverConfig,
|
||||||
layout_extractor: E,
|
layout_extractor: E,
|
||||||
|
layout_offset_extractor: E2,
|
||||||
) -> (String, Option<hir::Documentation>)
|
) -> (String, Option<hir::Documentation>)
|
||||||
where
|
where
|
||||||
D: HasAttrs + HirDisplay,
|
D: HasAttrs + HirDisplay,
|
||||||
E: Fn(&D) -> Option<V>,
|
E: Fn(&D) -> Result<Layout, LayoutError>,
|
||||||
V: Display,
|
E2: Fn(&Layout) -> Option<u64>,
|
||||||
{
|
{
|
||||||
let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
|
let mut label = def.display(db).to_string();
|
||||||
Some(layout) => format!("{} // {layout}", def.display(db)),
|
if let Some(layout) = render_memory_layout(
|
||||||
_ => def.display(db).to_string(),
|
config.memory_layout,
|
||||||
};
|
|| layout_extractor(&def),
|
||||||
|
layout_offset_extractor,
|
||||||
|
|_| None,
|
||||||
|
) {
|
||||||
|
format_to!(label, "{layout}");
|
||||||
|
}
|
||||||
let docs = def.attrs(db).docs();
|
let docs = def.attrs(db).docs();
|
||||||
(label, 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,
|
db: &RootDatabase,
|
||||||
def: D,
|
def: D,
|
||||||
config: &HoverConfig,
|
config: &HoverConfig,
|
||||||
value_extractor: E,
|
value_extractor: E,
|
||||||
layout_extractor: E2,
|
layout_extractor: E2,
|
||||||
|
layout_tag_extractor: E3,
|
||||||
) -> (String, Option<hir::Documentation>)
|
) -> (String, Option<hir::Documentation>)
|
||||||
where
|
where
|
||||||
D: HasAttrs + HirDisplay,
|
D: HasAttrs + HirDisplay,
|
||||||
E: Fn(&D) -> Option<V>,
|
E: Fn(&D) -> Option<V>,
|
||||||
E2: Fn(&D) -> Option<L>,
|
E2: Fn(&D) -> Result<Layout, LayoutError>,
|
||||||
|
E3: Fn(&Layout) -> Option<usize>,
|
||||||
V: Display,
|
V: Display,
|
||||||
L: Display,
|
|
||||||
{
|
{
|
||||||
let value = value_extractor(&def);
|
let value = value_extractor(&def);
|
||||||
let label = match value {
|
let mut label = match value {
|
||||||
Some(value) => format!("{} = {value}", def.display(db)),
|
Some(value) => format!("{} = {value}", def.display(db)),
|
||||||
None => def.display(db).to_string(),
|
None => def.display(db).to_string(),
|
||||||
};
|
};
|
||||||
let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
|
if let Some(layout) = render_memory_layout(
|
||||||
Some(layout) => format!("{} // {layout}", label),
|
config.memory_layout,
|
||||||
_ => label,
|
|| layout_extractor(&def),
|
||||||
};
|
|_| None,
|
||||||
|
layout_tag_extractor,
|
||||||
|
) {
|
||||||
|
format_to!(label, "{layout}");
|
||||||
|
}
|
||||||
let docs = def.attrs(db).docs();
|
let docs = def.attrs(db).docs();
|
||||||
(label, docs)
|
(label, docs)
|
||||||
}
|
}
|
||||||
|
@ -769,14 +760,87 @@ fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option<Mark
|
||||||
}
|
}
|
||||||
None => format!("{is_mut}self: {ty}"),
|
None => format!("{is_mut}self: {ty}"),
|
||||||
};
|
};
|
||||||
if config.memory_layout {
|
if let Some(layout) =
|
||||||
if let Ok(layout) = it.ty(db).layout(db) {
|
render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
|
||||||
format_to!(desc, " // size = {}, align = {}", layout.size(), layout.align());
|
{
|
||||||
}
|
format_to!(desc, "{layout}");
|
||||||
}
|
}
|
||||||
markup(None, desc, None)
|
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 {
|
struct KeywordHint {
|
||||||
description: String,
|
description: String,
|
||||||
keyword_mod: String,
|
keyword_mod: String,
|
||||||
|
|
|
@ -2,11 +2,18 @@ use expect_test::{expect, Expect};
|
||||||
use ide_db::base_db::{FileLoader, FileRange};
|
use ide_db::base_db::{FileLoader, FileRange};
|
||||||
use syntax::TextRange;
|
use syntax::TextRange;
|
||||||
|
|
||||||
use crate::{fixture, HoverConfig, HoverDocFormat};
|
use crate::{
|
||||||
|
fixture, HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
|
||||||
|
};
|
||||||
|
|
||||||
const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
|
const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
|
||||||
links_in_hover: false,
|
links_in_hover: false,
|
||||||
memory_layout: true,
|
memory_layout: Some(MemoryLayoutHoverConfig {
|
||||||
|
size: Some(MemoryLayoutHoverRenderKind::Both),
|
||||||
|
offset: Some(MemoryLayoutHoverRenderKind::Both),
|
||||||
|
alignment: Some(MemoryLayoutHoverRenderKind::Both),
|
||||||
|
niches: true,
|
||||||
|
}),
|
||||||
documentation: true,
|
documentation: true,
|
||||||
format: HoverDocFormat::Markdown,
|
format: HoverDocFormat::Markdown,
|
||||||
keywords: true,
|
keywords: true,
|
||||||
|
@ -62,7 +69,7 @@ fn check_hover_no_memory_layout(ra_fixture: &str, expect: Expect) {
|
||||||
let (analysis, position) = fixture::position(ra_fixture);
|
let (analysis, position) = fixture::position(ra_fixture);
|
||||||
let hover = analysis
|
let hover = analysis
|
||||||
.hover(
|
.hover(
|
||||||
&HoverConfig { memory_layout: false, ..HOVER_BASE_CONFIG },
|
&HoverConfig { memory_layout: None, ..HOVER_BASE_CONFIG },
|
||||||
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -237,7 +244,7 @@ fn main() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
*|*
|
*|*
|
||||||
```rust
|
```rust
|
||||||
{closure#0} // size = 8, align = 8
|
{closure#0} // size = 8, align = 8, niches = 1
|
||||||
impl Fn(i32) -> i32
|
impl Fn(i32) -> i32
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -292,7 +299,7 @@ fn main() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
*|*
|
*|*
|
||||||
```rust
|
```rust
|
||||||
{closure#0} // size = 16, align = 8
|
{closure#0} // size = 16 (0x10), align = 8, niches = 1
|
||||||
impl FnOnce()
|
impl FnOnce()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -320,7 +327,7 @@ fn main() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
*|*
|
*|*
|
||||||
```rust
|
```rust
|
||||||
{closure#0} // size = 8, align = 8
|
{closure#0} // size = 8, align = 8, niches = 1
|
||||||
impl FnMut()
|
impl FnMut()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -344,7 +351,7 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
```rust
|
```rust
|
||||||
{closure#0} // size = 8, align = 8
|
{closure#0} // size = 8, align = 8, niches = 1
|
||||||
impl FnOnce() -> S2
|
impl FnOnce() -> S2
|
||||||
```
|
```
|
||||||
Coerced to: &impl FnOnce() -> S2
|
Coerced to: &impl FnOnce() -> S2
|
||||||
|
@ -667,7 +674,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
field_a: u8 // size = 0x1, align = 0x1, offset = 0x4
|
field_a: u8 // size = 1, align = 1, offset = 4
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -692,7 +699,7 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
field_a: u32 // size = 0x4, align = 0x4, offset = 0x0
|
field_a: u32 // size = 4, align = 4, offset = 0
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -714,7 +721,7 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
field_a: u32 // size = 0x4, align = 0x4, offset = 0x0
|
field_a: u32 // size = 4, align = 4, offset = 0
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1528,7 +1535,7 @@ fn test_hover_function_pointer_show_identifiers() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
type foo = fn(a: i32, b: i32) -> i32 // size = 0x8, align = 0x8, niches = 1
|
type foo = fn(a: i32, b: i32) -> i32 // size = 8, align = 8, niches = 1
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1546,7 +1553,7 @@ fn test_hover_function_pointer_no_identifier() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
type foo = fn(i32, i32) -> i32 // size = 0x8, align = 0x8, niches = 1
|
type foo = fn(i32, i32) -> i32 // size = 8, align = 8, niches = 1
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1674,7 +1681,7 @@ fn foo() { let bar = Ba$0r; }
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct Bar // size = 0x0, align = 0x1
|
struct Bar // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1710,7 +1717,7 @@ fn foo() { let bar = Ba$0r; }
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct Bar // size = 0x0, align = 0x1
|
struct Bar // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1739,7 +1746,7 @@ fn foo() { let bar = Ba$0r; }
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct Bar // size = 0x0, align = 0x1
|
struct Bar // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1767,7 +1774,7 @@ pub struct B$0ar
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub struct Bar // size = 0x0, align = 0x1
|
pub struct Bar // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1794,7 +1801,7 @@ pub struct B$0ar
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub struct Bar // size = 0x0, align = 0x1
|
pub struct Bar // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -1883,7 +1890,7 @@ fn test_hover_layout_of_variant() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
Variant1(u8, u16) // size = 0x4
|
Variant1(u8, u16) // size = 4, align = 2
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1904,7 +1911,7 @@ fn test_hover_layout_of_enum() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
enum Foo // size = 0x10, align = 0x8, niches = 254
|
enum Foo // size = 16 (0x10), align = 8, niches = 254
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -3204,7 +3211,7 @@ fn main() {
|
||||||
*f*
|
*f*
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
f: &i32 // size = 8, align = 8
|
f: &i32 // size = 8, align = 8, niches = 1
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -3213,7 +3220,7 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
f: i32 // size = 0x4, align = 0x4, offset = 0x0
|
f: i32 // size = 4, align = 4, offset = 0
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -3353,7 +3360,7 @@ impl Foo {
|
||||||
*self*
|
*self*
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
self: &Foo // size = 8, align = 8
|
self: &Foo // size = 8, align = 8, niches = 1
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -3758,7 +3765,7 @@ type Fo$0o2 = Foo<2>;
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
type Foo2 = Foo<2> // size = 0x0, align = 0x1
|
type Foo2 = Foo<2> // size = 0, align = 1
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -3800,7 +3807,7 @@ enum E {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
A = 8
|
A = 8 // size = 1, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -3825,7 +3832,7 @@ enum E {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
A = 12 (0xC)
|
A = 12 (0xC) // size = 1, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -3851,7 +3858,7 @@ enum E {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
B = 2
|
B = 2 // size = 1, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -3877,7 +3884,7 @@ enum E {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
B = 5
|
B = 5 // size = 1, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -4411,7 +4418,7 @@ fn foo(e: E) {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
A = 3
|
A = 3 // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -4433,7 +4440,7 @@ fn main() {
|
||||||
*tile4*
|
*tile4*
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let tile4: [u32; 8] // size = 32, align = 4
|
let tile4: [u32; 8] // size = 32 (0x20), align = 4
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -4669,7 +4676,7 @@ pub fn gimme() -> theitem::TheItem {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub struct TheItem // size = 0x0, align = 0x1
|
pub struct TheItem // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -4817,7 +4824,7 @@ mod string {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct String // size = 0x0, align = 0x1
|
struct String // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -5486,7 +5493,7 @@ foo_macro!(
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub struct Foo // size = 0x0, align = 0x1
|
pub struct Foo // size = 0, align = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -5511,7 +5518,7 @@ pub struct Foo(i32);
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub struct Foo // size = 0x4, align = 0x4
|
pub struct Foo // size = 4, align = 4
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -5610,7 +5617,7 @@ enum Enum {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
RecordV { field: u32 } // size = 0x4
|
RecordV { field: u32 } // size = 4, align = 4
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -5632,7 +5639,7 @@ enum Enum {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
field: u32 // size = 0x4, align = 0x4
|
field: u32 // size = 4, align = 4
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -6134,7 +6141,7 @@ fn test() {
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
f: u32 // size = 0x4, align = 0x4, offset = 0x0
|
f: u32 // size = 4, align = 4, offset = 0
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -84,7 +84,10 @@ pub use crate::{
|
||||||
file_structure::{StructureNode, StructureNodeKind},
|
file_structure::{StructureNode, StructureNodeKind},
|
||||||
folding_ranges::{Fold, FoldKind},
|
folding_ranges::{Fold, FoldKind},
|
||||||
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
||||||
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
|
hover::{
|
||||||
|
HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
|
||||||
|
MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
|
||||||
|
},
|
||||||
inlay_hints::{
|
inlay_hints::{
|
||||||
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
|
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
|
||||||
InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
|
InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
|
||||||
|
|
|
@ -138,7 +138,7 @@ impl StaticIndex<'_> {
|
||||||
});
|
});
|
||||||
let hover_config = HoverConfig {
|
let hover_config = HoverConfig {
|
||||||
links_in_hover: true,
|
links_in_hover: true,
|
||||||
memory_layout: true,
|
memory_layout: None,
|
||||||
documentation: true,
|
documentation: true,
|
||||||
keywords: true,
|
keywords: true,
|
||||||
format: crate::HoverDocFormat::Markdown,
|
format: crate::HoverDocFormat::Markdown,
|
||||||
|
|
|
@ -14,7 +14,7 @@ use flycheck::FlycheckConfig;
|
||||||
use ide::{
|
use ide::{
|
||||||
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
|
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
|
||||||
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
|
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
|
||||||
JoinLinesConfig, Snippet, SnippetScope,
|
JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
||||||
|
@ -317,8 +317,16 @@ config_data! {
|
||||||
hover_documentation_keywords_enable: bool = "true",
|
hover_documentation_keywords_enable: bool = "true",
|
||||||
/// Use markdown syntax for links on hover.
|
/// Use markdown syntax for links on hover.
|
||||||
hover_links_enable: bool = "true",
|
hover_links_enable: bool = "true",
|
||||||
|
/// How to render the align information in a memory layout hover.
|
||||||
|
hover_memoryLayout_alignment: Option<MemoryLayoutHoverRenderKindDef> = "\"hexadecimal\"",
|
||||||
/// Whether to show memory layout data on hover.
|
/// Whether to show memory layout data on hover.
|
||||||
hover_memoryLayout_enable: bool = "true",
|
hover_memoryLayout_enable: bool = "true",
|
||||||
|
/// How to render the niche information in a memory layout hover.
|
||||||
|
hover_memoryLayout_niches: Option<bool> = "false",
|
||||||
|
/// How to render the offset information in a memory layout hover.
|
||||||
|
hover_memoryLayout_offset: Option<MemoryLayoutHoverRenderKindDef> = "\"hexadecimal\"",
|
||||||
|
/// How to render the size information in a memory layout hover.
|
||||||
|
hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = "\"both\"",
|
||||||
|
|
||||||
/// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
|
/// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
|
||||||
imports_granularity_enforce: bool = "false",
|
imports_granularity_enforce: bool = "false",
|
||||||
|
@ -1514,9 +1522,19 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hover(&self) -> HoverConfig {
|
pub fn hover(&self) -> HoverConfig {
|
||||||
|
let mem_kind = |kind| match kind {
|
||||||
|
MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
|
||||||
|
MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
|
||||||
|
MemoryLayoutHoverRenderKindDef::Hexadecimal => MemoryLayoutHoverRenderKind::Hexadecimal,
|
||||||
|
};
|
||||||
HoverConfig {
|
HoverConfig {
|
||||||
links_in_hover: self.data.hover_links_enable,
|
links_in_hover: self.data.hover_links_enable,
|
||||||
memory_layout: self.data.hover_memoryLayout_enable,
|
memory_layout: self.data.hover_memoryLayout_enable.then_some(MemoryLayoutHoverConfig {
|
||||||
|
size: self.data.hover_memoryLayout_size.map(mem_kind),
|
||||||
|
offset: self.data.hover_memoryLayout_offset.map(mem_kind),
|
||||||
|
alignment: self.data.hover_memoryLayout_alignment.map(mem_kind),
|
||||||
|
niches: self.data.hover_memoryLayout_niches.unwrap_or_default(),
|
||||||
|
}),
|
||||||
documentation: self.data.hover_documentation_enable,
|
documentation: self.data.hover_documentation_enable,
|
||||||
format: {
|
format: {
|
||||||
let is_markdown = try_or_def!(self
|
let is_markdown = try_or_def!(self
|
||||||
|
@ -1726,6 +1744,9 @@ mod de_unit_v {
|
||||||
named_unit_variant!(reborrow);
|
named_unit_variant!(reborrow);
|
||||||
named_unit_variant!(fieldless);
|
named_unit_variant!(fieldless);
|
||||||
named_unit_variant!(with_block);
|
named_unit_variant!(with_block);
|
||||||
|
named_unit_variant!(decimal);
|
||||||
|
named_unit_variant!(hexadecimal);
|
||||||
|
named_unit_variant!(both);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, Copy)]
|
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||||
|
@ -1956,6 +1977,18 @@ enum WorkspaceSymbolSearchKindDef {
|
||||||
AllSymbols,
|
AllSymbols,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Copy, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MemoryLayoutHoverRenderKindDef {
|
||||||
|
#[serde(deserialize_with = "de_unit_v::decimal")]
|
||||||
|
Decimal,
|
||||||
|
#[serde(deserialize_with = "de_unit_v::hexadecimal")]
|
||||||
|
Hexadecimal,
|
||||||
|
#[serde(deserialize_with = "de_unit_v::both")]
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! _config_data {
|
macro_rules! _config_data {
|
||||||
(struct $name:ident {
|
(struct $name:ident {
|
||||||
$(
|
$(
|
||||||
|
@ -2038,7 +2071,9 @@ fn get_field<T: DeserializeOwned>(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| serde_json::from_str(default).unwrap())
|
.unwrap_or_else(|| {
|
||||||
|
serde_json::from_str(default).unwrap_or_else(|e| panic!("{e} on: `{default}`"))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value {
|
fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value {
|
||||||
|
@ -2366,6 +2401,22 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
|
||||||
"`hide`: Shows `...` for every closure type",
|
"`hide`: Shows `...` for every closure type",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"Option<MemoryLayoutHoverRenderKindDef>" => set! {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["both", "decimal", "hexadecimal", ],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"Render as 12 (0xC)",
|
||||||
|
"Render as 12",
|
||||||
|
"Render as 0xC"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
_ => panic!("missing entry for {ty}: {default}"),
|
_ => panic!("missing entry for {ty}: {default}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -428,11 +428,31 @@ Whether to show keyword hover popups. Only applies when
|
||||||
--
|
--
|
||||||
Use markdown syntax for links on hover.
|
Use markdown syntax for links on hover.
|
||||||
--
|
--
|
||||||
|
[[rust-analyzer.hover.memoryLayout.alignment]]rust-analyzer.hover.memoryLayout.alignment (default: `"hexadecimal"`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
How to render the align information in a memory layout hover.
|
||||||
|
--
|
||||||
[[rust-analyzer.hover.memoryLayout.enable]]rust-analyzer.hover.memoryLayout.enable (default: `true`)::
|
[[rust-analyzer.hover.memoryLayout.enable]]rust-analyzer.hover.memoryLayout.enable (default: `true`)::
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
Whether to show memory layout data on hover.
|
Whether to show memory layout data on hover.
|
||||||
--
|
--
|
||||||
|
[[rust-analyzer.hover.memoryLayout.niches]]rust-analyzer.hover.memoryLayout.niches (default: `false`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
How to render the niche information in a memory layout hover.
|
||||||
|
--
|
||||||
|
[[rust-analyzer.hover.memoryLayout.offset]]rust-analyzer.hover.memoryLayout.offset (default: `"hexadecimal"`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
How to render the offset information in a memory layout hover.
|
||||||
|
--
|
||||||
|
[[rust-analyzer.hover.memoryLayout.size]]rust-analyzer.hover.memoryLayout.size (default: `"both"`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
How to render the size information in a memory layout hover.
|
||||||
|
--
|
||||||
[[rust-analyzer.imports.granularity.enforce]]rust-analyzer.imports.granularity.enforce (default: `false`)::
|
[[rust-analyzer.imports.granularity.enforce]]rust-analyzer.imports.granularity.enforce (default: `false`)::
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
|
|
|
@ -966,11 +966,85 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.hover.memoryLayout.alignment": {
|
||||||
|
"markdownDescription": "How to render the align information in a memory layout hover.",
|
||||||
|
"default": "hexadecimal",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"both",
|
||||||
|
"decimal",
|
||||||
|
"hexadecimal"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"Render as 12 (0xC)",
|
||||||
|
"Render as 12",
|
||||||
|
"Render as 0xC"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"rust-analyzer.hover.memoryLayout.enable": {
|
"rust-analyzer.hover.memoryLayout.enable": {
|
||||||
"markdownDescription": "Whether to show memory layout data on hover.",
|
"markdownDescription": "Whether to show memory layout data on hover.",
|
||||||
"default": true,
|
"default": true,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.hover.memoryLayout.niches": {
|
||||||
|
"markdownDescription": "How to render the niche information in a memory layout hover.",
|
||||||
|
"default": false,
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
"boolean"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rust-analyzer.hover.memoryLayout.offset": {
|
||||||
|
"markdownDescription": "How to render the offset information in a memory layout hover.",
|
||||||
|
"default": "hexadecimal",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"both",
|
||||||
|
"decimal",
|
||||||
|
"hexadecimal"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"Render as 12 (0xC)",
|
||||||
|
"Render as 12",
|
||||||
|
"Render as 0xC"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rust-analyzer.hover.memoryLayout.size": {
|
||||||
|
"markdownDescription": "How to render the size information in a memory layout hover.",
|
||||||
|
"default": "both",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"both",
|
||||||
|
"decimal",
|
||||||
|
"hexadecimal"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"Render as 12 (0xC)",
|
||||||
|
"Render as 12",
|
||||||
|
"Render as 0xC"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"rust-analyzer.imports.granularity.enforce": {
|
"rust-analyzer.imports.granularity.enforce": {
|
||||||
"markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
|
"markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|
Loading…
Reference in a new issue