Skip to content

Commit

Permalink
Auto merge of #15406 - lowr:fix/panic-missing-impl-self-ty, r=lnicola
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Aug 6, 2023
2 parents 70fa270 + 5829174 commit baee6b3
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
38 changes: 33 additions & 5 deletions crates/ide-assists/src/handlers/generate_default_from_new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
// Generates default implementation from new method.
//
// ```
// # //- minicore: default
// struct Example { _inner: () }
//
// impl Example {
Expand Down Expand Up @@ -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 self_ty = impl_.self_ty()?;
if is_default_implemented(ctx, &impl_) {
cov_mark::hit!(default_block_is_already_present);
cov_mark::hit!(struct_in_module_with_default);
Expand All @@ -70,15 +72,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
let default_code = " fn default() -> Self {
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);
},
)
}

// 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 {
let impl_ty = impl_.self_ty().unwrap();
fn generate_trait_impl_text_from_impl(
impl_: &ast::Impl,
self_ty: ast::Type,
trait_text: &str,
code: &str,
) -> String {
let generic_params = impl_.generic_param_list().map(|generic_params| {
let lifetime_params =
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
Expand Down Expand Up @@ -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 {
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() {
Some(where_clause) => {
Expand All @@ -136,7 +142,9 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool {
let default = FamousDefs(&ctx.sema, krate).core_default_Default();
let default_trait = match default {
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, &[])
Expand Down Expand Up @@ -480,6 +488,7 @@ impl Example {
check_assist_not_applicable(
generate_default_from_new,
r#"
//- minicore: default
struct Example { _inner: () }
impl Example {
Expand Down Expand Up @@ -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 {} }");
}
}
1 change: 1 addition & 0 deletions crates/ide-assists/src/tests/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,7 @@ fn doctest_generate_default_from_new() {
check_doc_test(
"generate_default_from_new",
r#####"
//- minicore: default
struct Example { _inner: () }
impl Example {
Expand Down

0 comments on commit baee6b3

Please sign in to comment.