diff --git a/crates/ide-assists/src/handlers/generate_impl.rs b/crates/ide-assists/src/handlers/generate_impl.rs index 9af26c04eb..1bea220f38 100644 --- a/crates/ide-assists/src/handlers/generate_impl.rs +++ b/crates/ide-assists/src/handlers/generate_impl.rs @@ -7,8 +7,8 @@ use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assi // Adds a new inherent impl for a type. // // ``` -// struct Ctx { -// data: T,$0 +// struct Ctx$0 { +// data: T, // } // ``` // -> @@ -26,6 +26,10 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio let name = nominal.name()?; let target = nominal.syntax().text_range(); + if let Some(_) = ctx.find_node_at_offset::() { + return None; + } + acc.add( AssistId("generate_impl", AssistKind::Generate), format!("Generate impl for `{name}`"), @@ -52,139 +56,171 @@ mod tests { use super::*; - // FIXME: break up into separate test fns #[test] fn test_add_impl() { - check_assist( - generate_impl, - "struct Foo {$0}\n", - "struct Foo {}\n\nimpl Foo {\n $0\n}\n", - ); - check_assist( - generate_impl, - "struct Foo {$0}", - "struct Foo {}\n\nimpl Foo {\n $0\n}", - ); - check_assist( - generate_impl, - "struct Foo<'a, T: Foo<'a>> {$0}", - "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", - ); check_assist( generate_impl, r#" - struct MyOwnArray {}$0"#, + struct Foo$0 {} + "#, r#" - struct MyOwnArray {} + struct Foo {} - impl MyOwnArray { - $0 - }"#, - ); - check_assist( - generate_impl, - r#" - #[cfg(feature = "foo")] - struct Foo<'a, T: Foo<'a>> {$0}"#, - r#" - #[cfg(feature = "foo")] - struct Foo<'a, T: Foo<'a>> {} - - #[cfg(feature = "foo")] - impl<'a, T: Foo<'a>> Foo<'a, T> { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - #[cfg(not(feature = "foo"))] - struct Foo<'a, T: Foo<'a>> {$0}"#, - r#" - #[cfg(not(feature = "foo"))] - struct Foo<'a, T: Foo<'a>> {} - - #[cfg(not(feature = "foo"))] - impl<'a, T: Foo<'a>> Foo<'a, T> { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - struct Defaulted {}$0"#, - r#" - struct Defaulted {} - - impl Defaulted { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}$0"#, - r#" - struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} - - impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#" - struct Defaulted {}$0"#, - r#" - struct Defaulted {} - - impl Defaulted { - $0 - }"#, - ); - - check_assist( - generate_impl, - r#"pub trait Trait {} -struct Struct$0 -where - T: Trait, -{ - inner: T, -}"#, - r#"pub trait Trait {} -struct Struct -where - T: Trait, -{ - inner: T, -} - -impl Struct -where - T: Trait, -{ - $0 -}"#, + impl Foo { + $0 + } + "#, ); } #[test] - fn add_impl_target() { + fn test_add_impl_with_generics() { + check_assist( + generate_impl, + r#" + struct Foo$0 {} + "#, + r#" + struct Foo {} + + impl Foo { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_generics_and_lifetime_parameters() { + check_assist( + generate_impl, + r#" + struct Foo<'a, T: Foo<'a>>$0 {} + "#, + r#" + struct Foo<'a, T: Foo<'a>> {} + + impl<'a, T: Foo<'a>> Foo<'a, T> { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_attributes() { + check_assist( + generate_impl, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo$0<'a>> {} + "#, + r#" + #[cfg(feature = "foo")] + struct Foo<'a, T: Foo<'a>> {} + + #[cfg(feature = "foo")] + impl<'a, T: Foo<'a>> Foo<'a, T> { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_default_generic() { + check_assist( + generate_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl Defaulted { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_constrained_default_generic() { + check_assist( + generate_impl, + r#" + struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + "#, + r#" + struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {} + + impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_const_defaulted_generic() { + check_assist( + generate_impl, + r#" + struct Defaulted$0 {} + "#, + r#" + struct Defaulted {} + + impl Defaulted { + $0 + } + "#, + ); + } + + #[test] + fn test_add_impl_with_trait_constraint() { + check_assist( + generate_impl, + r#" + pub trait Trait {} + struct Struct$0 + where + T: Trait, + { + inner: T, + } + "#, + r#" + pub trait Trait {} + struct Struct + where + T: Trait, + { + inner: T, + } + + impl Struct + where + T: Trait, + { + $0 + } + "#, + ); + } + + #[test] + fn add_trait_impl_target() { check_assist_target( generate_impl, - " -struct SomeThingIrrelevant; -/// Has a lifetime parameter -struct Foo<'a, T: Foo<'a>> {$0} -struct EvenMoreIrrelevant; -", - "/// Has a lifetime parameter -struct Foo<'a, T: Foo<'a>> {}", + r#" + struct SomeThingIrrelevant; + /// Has a lifetime parameter + struct Foo$0<'a, T: Foo<'a>> {} + struct EvenMoreIrrelevant; + "#, + "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}", ); } } diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 67657b61bb..d797f07767 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1249,8 +1249,8 @@ fn doctest_generate_impl() { check_doc_test( "generate_impl", r#####" -struct Ctx { - data: T,$0 +struct Ctx$0 { + data: T, } "#####, r#####"