mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-27 02:06:57 +00:00
Calculate drop glue and show it on hover
Also fix the `needs_drop()` intrinsic. Unions also need this information (to err if they have a drop-needing field), but this will come in a follow-up PR.
This commit is contained in:
parent
2b485d7f23
commit
100e166bb1
13 changed files with 1002 additions and 6 deletions
|
|
@ -38,6 +38,7 @@ pub struct HoverConfig {
|
|||
pub max_fields_count: Option<usize>,
|
||||
pub max_enum_variants_count: Option<usize>,
|
||||
pub max_subst_ty_len: SubstTyLen,
|
||||
pub show_drop_glue: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{env, mem, ops::Not};
|
|||
|
||||
use either::Either;
|
||||
use hir::{
|
||||
db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind,
|
||||
db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DropGlue,
|
||||
DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError,
|
||||
MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef,
|
||||
};
|
||||
|
|
@ -629,6 +629,89 @@ pub(super) fn definition(
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let drop_info = || {
|
||||
if !config.show_drop_glue {
|
||||
return None;
|
||||
}
|
||||
let drop_info = match def {
|
||||
Definition::Field(field) => {
|
||||
DropInfo { drop_glue: field.ty(db).drop_glue(db), has_dtor: None }
|
||||
}
|
||||
Definition::Adt(Adt::Struct(strukt)) => {
|
||||
let struct_drop_glue = strukt.ty_placeholders(db).drop_glue(db);
|
||||
let mut fields_drop_glue = strukt
|
||||
.fields(db)
|
||||
.iter()
|
||||
.map(|field| field.ty(db).drop_glue(db))
|
||||
.max()
|
||||
.unwrap_or(DropGlue::None);
|
||||
let has_dtor = match (fields_drop_glue, struct_drop_glue) {
|
||||
(DropGlue::None, _) => struct_drop_glue != DropGlue::None,
|
||||
(_, DropGlue::None) => {
|
||||
// This is `ManuallyDrop`.
|
||||
fields_drop_glue = DropGlue::None;
|
||||
false
|
||||
}
|
||||
(_, _) => struct_drop_glue > fields_drop_glue,
|
||||
};
|
||||
DropInfo { drop_glue: fields_drop_glue, has_dtor: Some(has_dtor) }
|
||||
}
|
||||
// Unions cannot have fields with drop glue.
|
||||
Definition::Adt(Adt::Union(union)) => DropInfo {
|
||||
drop_glue: DropGlue::None,
|
||||
has_dtor: Some(union.ty_placeholders(db).drop_glue(db) != DropGlue::None),
|
||||
},
|
||||
Definition::Adt(Adt::Enum(enum_)) => {
|
||||
let enum_drop_glue = enum_.ty_placeholders(db).drop_glue(db);
|
||||
let fields_drop_glue = enum_
|
||||
.variants(db)
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
variant
|
||||
.fields(db)
|
||||
.iter()
|
||||
.map(|field| field.ty(db).drop_glue(db))
|
||||
.max()
|
||||
.unwrap_or(DropGlue::None)
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(DropGlue::None);
|
||||
DropInfo {
|
||||
drop_glue: fields_drop_glue,
|
||||
has_dtor: Some(enum_drop_glue > fields_drop_glue),
|
||||
}
|
||||
}
|
||||
Definition::Variant(variant) => {
|
||||
let fields_drop_glue = variant
|
||||
.fields(db)
|
||||
.iter()
|
||||
.map(|field| field.ty(db).drop_glue(db))
|
||||
.max()
|
||||
.unwrap_or(DropGlue::None);
|
||||
DropInfo { drop_glue: fields_drop_glue, has_dtor: None }
|
||||
}
|
||||
Definition::TypeAlias(type_alias) => {
|
||||
DropInfo { drop_glue: type_alias.ty_placeholders(db).drop_glue(db), has_dtor: None }
|
||||
}
|
||||
Definition::Local(local) => {
|
||||
DropInfo { drop_glue: local.ty(db).drop_glue(db), has_dtor: None }
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let rendered_drop_glue = match drop_info.drop_glue {
|
||||
DropGlue::None => "does not contain types with destructors (drop glue)",
|
||||
DropGlue::DependOnParams => {
|
||||
"may contain types with destructors (drop glue) depending on type parameters"
|
||||
}
|
||||
DropGlue::HasDropGlue => "contain types with destructors (drop glue)",
|
||||
};
|
||||
Some(match drop_info.has_dtor {
|
||||
Some(true) => format!("{}; has a destructor", rendered_drop_glue),
|
||||
Some(false) => format!("{}; doesn't have a destructor", rendered_drop_glue),
|
||||
None => rendered_drop_glue.to_owned(),
|
||||
})
|
||||
};
|
||||
|
||||
let dyn_compatibility_info = || match def {
|
||||
Definition::Trait(it) => {
|
||||
let mut dyn_compatibility_info = String::new();
|
||||
|
|
@ -661,6 +744,10 @@ pub(super) fn definition(
|
|||
extra.push_str("\n___\n");
|
||||
extra.push_str(&dyn_compatibility_info);
|
||||
}
|
||||
if let Some(drop_info) = drop_info() {
|
||||
extra.push_str("\n___\n");
|
||||
extra.push_str(&drop_info);
|
||||
}
|
||||
}
|
||||
let mut desc = String::new();
|
||||
desc.push_str(&label);
|
||||
|
|
@ -703,6 +790,12 @@ pub(super) fn definition(
|
|||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DropInfo {
|
||||
drop_glue: DropGlue,
|
||||
has_dtor: Option<bool>,
|
||||
}
|
||||
|
||||
pub(super) fn literal(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
token: SyntaxToken,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -187,6 +187,7 @@ impl StaticIndex<'_> {
|
|||
max_fields_count: Some(5),
|
||||
max_enum_variants_count: Some(5),
|
||||
max_subst_ty_len: SubstTyLen::Unlimited,
|
||||
show_drop_glue: true,
|
||||
};
|
||||
let tokens = tokens.filter(|token| {
|
||||
matches!(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue