mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
feat: Implement object safety
This commit is contained in:
parent
06a40a61b0
commit
6520a43ca3
19 changed files with 1194 additions and 66 deletions
|
@ -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(¬able_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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue