mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Auto merge of #15406 - lowr:fix/panic-missing-impl-self-ty, r=lnicola
Don't provide `generate_default_from_new` when impl self ty is missing Also don't provide the assist when the `Default` trait can't be found. Part of #15398
This commit is contained in:
commit
baee6b338b
2 changed files with 34 additions and 5 deletions
|
@ -15,6 +15,7 @@ use crate::{
|
||||||
// Generates default implementation from new method.
|
// Generates default implementation from new method.
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
|
// # //- minicore: default
|
||||||
// struct Example { _inner: () }
|
// struct Example { _inner: () }
|
||||||
//
|
//
|
||||||
// impl Example {
|
// impl Example {
|
||||||
|
@ -54,6 +55,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
}
|
}
|
||||||
|
|
||||||
let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
|
let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
|
||||||
|
let self_ty = impl_.self_ty()?;
|
||||||
if is_default_implemented(ctx, &impl_) {
|
if is_default_implemented(ctx, &impl_) {
|
||||||
cov_mark::hit!(default_block_is_already_present);
|
cov_mark::hit!(default_block_is_already_present);
|
||||||
cov_mark::hit!(struct_in_module_with_default);
|
cov_mark::hit!(struct_in_module_with_default);
|
||||||
|
@ -70,15 +72,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
let default_code = " fn default() -> Self {
|
let default_code = " fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}";
|
}";
|
||||||
let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
|
let code = generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code);
|
||||||
builder.insert(insert_location.end(), code);
|
builder.insert(insert_location.end(), code);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: based on from utils::generate_impl_text_inner
|
// FIXME: based on from utils::generate_impl_text_inner
|
||||||
fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
|
fn generate_trait_impl_text_from_impl(
|
||||||
let impl_ty = impl_.self_ty().unwrap();
|
impl_: &ast::Impl,
|
||||||
|
self_ty: ast::Type,
|
||||||
|
trait_text: &str,
|
||||||
|
code: &str,
|
||||||
|
) -> String {
|
||||||
let generic_params = impl_.generic_param_list().map(|generic_params| {
|
let generic_params = impl_.generic_param_list().map(|generic_params| {
|
||||||
let lifetime_params =
|
let lifetime_params =
|
||||||
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
|
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
|
||||||
|
@ -109,7 +115,7 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code:
|
||||||
if let Some(generic_params) = &generic_params {
|
if let Some(generic_params) = &generic_params {
|
||||||
format_to!(buf, "{generic_params}")
|
format_to!(buf, "{generic_params}")
|
||||||
}
|
}
|
||||||
format_to!(buf, " {trait_text} for {impl_ty}");
|
format_to!(buf, " {trait_text} for {self_ty}");
|
||||||
|
|
||||||
match impl_.where_clause() {
|
match impl_.where_clause() {
|
||||||
Some(where_clause) => {
|
Some(where_clause) => {
|
||||||
|
@ -136,7 +142,9 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool {
|
||||||
let default = FamousDefs(&ctx.sema, krate).core_default_Default();
|
let default = FamousDefs(&ctx.sema, krate).core_default_Default();
|
||||||
let default_trait = match default {
|
let default_trait = match default {
|
||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
None => return false,
|
// Return `true` to avoid providing the assist because it makes no sense
|
||||||
|
// to impl `Default` when it's missing.
|
||||||
|
None => return true,
|
||||||
};
|
};
|
||||||
|
|
||||||
ty.impls_trait(db, default_trait, &[])
|
ty.impls_trait(db, default_trait, &[])
|
||||||
|
@ -480,6 +488,7 @@ impl Example {
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
generate_default_from_new,
|
generate_default_from_new,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: default
|
||||||
struct Example { _inner: () }
|
struct Example { _inner: () }
|
||||||
|
|
||||||
impl Example {
|
impl Example {
|
||||||
|
@ -655,4 +664,23 @@ mod test {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_applicable_when_default_lang_item_is_missing() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
generate_default_from_new,
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
fn new$0() -> Self {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_applicable_for_missing_self_ty() {
|
||||||
|
// Regression test for #15398.
|
||||||
|
check_assist_not_applicable(generate_default_from_new, "impl { fn new$0() -> Self {} }");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -952,6 +952,7 @@ fn doctest_generate_default_from_new() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
"generate_default_from_new",
|
"generate_default_from_new",
|
||||||
r#####"
|
r#####"
|
||||||
|
//- minicore: default
|
||||||
struct Example { _inner: () }
|
struct Example { _inner: () }
|
||||||
|
|
||||||
impl Example {
|
impl Example {
|
||||||
|
|
Loading…
Reference in a new issue