mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 21:25:25 +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…
	
	Add table
		Add a link
		
	
		Reference in a new issue