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.rs74
1 files changed, 73 insertions, 1 deletions
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 3e41b42be4..ead2d45847 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -4,7 +4,8 @@ use std::{mem, ops::Not};
use either::Either;
use hir::{
Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout,
- LayoutError, Name, Semantics, Trait, Type, TypeInfo,
+ LayoutError, MethodViolationCode, Name, ObjectSafetyViolation, Semantics, Trait, Type,
+ TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
@@ -526,6 +527,14 @@ pub(super) fn definition(
_ => None,
};
+ let object_safety_info = if let Definition::Trait(it) = def {
+ let mut object_safety_info = String::new();
+ render_object_safety(db, &mut object_safety_info, it.object_safety(db));
+ Some(object_safety_info)
+ } else {
+ None
+ };
+
let mut desc = String::new();
if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits, edition) {
desc.push_str(&notable_traits);
@@ -535,6 +544,10 @@ pub(super) fn definition(
desc.push_str(&layout_info);
desc.push('\n');
}
+ if let Some(object_safety_info) = object_safety_info {
+ desc.push_str(&object_safety_info);
+ desc.push('\n');
+ }
desc.push_str(&label);
if let Some(value) = value {
desc.push_str(" = ");
@@ -964,3 +977,62 @@ fn keyword_hints(
_ => KeywordHint::new(token.text().to_owned(), format!("{}_keyword", token.text())),
}
}
+
+fn render_object_safety(
+ db: &RootDatabase,
+ buf: &mut String,
+ safety: Option<ObjectSafetyViolation>,
+) {
+ let Some(osv) = safety else {
+ buf.push_str("// Object Safety: Yes");
+ return;
+ };
+ buf.push_str("// Object Safety: No\n// - Reason: ");
+ match osv {
+ ObjectSafetyViolation::SizedSelf => {
+ buf.push_str("has a `Self: Sized` bound");
+ }
+ ObjectSafetyViolation::SelfReferential => {
+ buf.push_str("has a bound that references `Self`");
+ }
+ ObjectSafetyViolation::Method(func, mvc) => {
+ let name = hir::Function::from(func).name(db);
+ format_to!(
+ buf,
+ "has a method `{}` that is non dispatchable because of:\n// - ",
+ name.as_str()
+ );
+ let desc = match mvc {
+ MethodViolationCode::StaticMethod => "missing a receiver",
+ MethodViolationCode::ReferencesSelfInput => "a parameter references `Self`",
+ MethodViolationCode::ReferencesSelfOutput => "the return type references `Self`",
+ MethodViolationCode::ReferencesImplTraitInTrait => {
+ "the return type contains `impl Trait`"
+ }
+ MethodViolationCode::AsyncFn => "being async",
+ MethodViolationCode::WhereClauseReferencesSelf => {
+ "a where clause references `Self`"
+ }
+ MethodViolationCode::Generic => "a non-lifetime generic parameter",
+ MethodViolationCode::UndispatchableReceiver => "a non-dispatchable receiver type",
+ };
+ buf.push_str(desc);
+ }
+ ObjectSafetyViolation::AssocConst(const_) => {
+ let name = hir::Const::from(const_).name(db);
+ if let Some(name) = name {
+ format_to!(buf, "has an associated constant `{}`", name.as_str());
+ } else {
+ buf.push_str("has an associated constant");
+ }
+ }
+ ObjectSafetyViolation::GAT(alias) => {
+ let name = hir::TypeAlias::from(alias).name(db);
+ format_to!(buf, "has a generic associated type `{}`", name.as_str());
+ }
+ ObjectSafetyViolation::HasNonSafeSuperTrait(super_trait) => {
+ let name = hir::Trait::from(super_trait).name(db);
+ format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str());
+ }
+ }
+}