Skip to content

Commit 469f620

Browse files
author
Mihail Mihov
committed
Combine generate_impl and generate_trait_impl into a single file
1 parent 0bd11f8 commit 469f620

File tree

3 files changed

+222
-230
lines changed

3 files changed

+222
-230
lines changed

crates/ide-assists/src/handlers/generate_impl.rs

Lines changed: 221 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use syntax::ast::{self, AstNode, HasName};
22

3-
use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
3+
use crate::{
4+
utils::{generate_impl_text, generate_trait_impl_text},
5+
AssistContext, AssistId, AssistKind, Assists,
6+
};
47

58
// Assist: generate_impl
69
//
@@ -50,6 +53,54 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
5053
)
5154
}
5255

56+
// Assist: generate_trait_impl
57+
//
58+
// Adds a new trait impl for a type.
59+
//
60+
// ```
61+
// struct $0Ctx<T: Clone> {
62+
// data: T,
63+
// }
64+
// ```
65+
// ->
66+
// ```
67+
// struct Ctx<T: Clone> {
68+
// data: T,
69+
// }
70+
//
71+
// impl<T: Clone> $0 for Ctx<T> {
72+
//
73+
// }
74+
// ```
75+
pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
76+
let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
77+
let name = nominal.name()?;
78+
let target = nominal.syntax().text_range();
79+
80+
if let Some(_) = ctx.find_node_at_offset::<ast::RecordFieldList>() {
81+
return None;
82+
}
83+
84+
acc.add(
85+
AssistId("generate_trait_impl", AssistKind::Generate),
86+
format!("Generate trait impl for `{name}`"),
87+
target,
88+
|edit| {
89+
let start_offset = nominal.syntax().text_range().end();
90+
match ctx.config.snippet_cap {
91+
Some(cap) => {
92+
let snippet = generate_trait_impl_text(&nominal, "$0", "");
93+
edit.insert_snippet(cap, start_offset, snippet);
94+
}
95+
None => {
96+
let text = generate_trait_impl_text(&nominal, "", "");
97+
edit.insert(start_offset, text);
98+
}
99+
}
100+
},
101+
)
102+
}
103+
53104
#[cfg(test)]
54105
mod tests {
55106
use crate::tests::{check_assist, check_assist_target};
@@ -211,7 +262,7 @@ mod tests {
211262
}
212263

213264
#[test]
214-
fn add_trait_impl_target() {
265+
fn add_impl_target() {
215266
check_assist_target(
216267
generate_impl,
217268
r#"
@@ -223,4 +274,172 @@ mod tests {
223274
"/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}",
224275
);
225276
}
277+
278+
#[test]
279+
fn test_add_trait_impl() {
280+
check_assist(
281+
generate_trait_impl,
282+
r#"
283+
struct Foo$0 {}
284+
"#,
285+
r#"
286+
struct Foo {}
287+
288+
impl $0 for Foo {
289+
290+
}
291+
"#,
292+
);
293+
}
294+
295+
#[test]
296+
fn test_add_trait_impl_with_generics() {
297+
check_assist(
298+
generate_trait_impl,
299+
r#"
300+
struct Foo$0<T: Clone> {}
301+
"#,
302+
r#"
303+
struct Foo<T: Clone> {}
304+
305+
impl<T: Clone> $0 for Foo<T> {
306+
307+
}
308+
"#,
309+
);
310+
}
311+
312+
#[test]
313+
fn test_add_trait_impl_with_generics_and_lifetime_parameters() {
314+
check_assist(
315+
generate_trait_impl,
316+
r#"
317+
struct Foo<'a, T: Foo<'a>>$0 {}
318+
"#,
319+
r#"
320+
struct Foo<'a, T: Foo<'a>> {}
321+
322+
impl<'a, T: Foo<'a>> $0 for Foo<'a, T> {
323+
324+
}
325+
"#,
326+
);
327+
}
328+
329+
#[test]
330+
fn test_add_trait_impl_with_attributes() {
331+
check_assist(
332+
generate_trait_impl,
333+
r#"
334+
#[cfg(feature = "foo")]
335+
struct Foo<'a, T: Foo$0<'a>> {}
336+
"#,
337+
r#"
338+
#[cfg(feature = "foo")]
339+
struct Foo<'a, T: Foo<'a>> {}
340+
341+
#[cfg(feature = "foo")]
342+
impl<'a, T: Foo<'a>> $0 for Foo<'a, T> {
343+
344+
}
345+
"#,
346+
);
347+
}
348+
349+
#[test]
350+
fn test_add_trait_impl_with_default_generic() {
351+
check_assist(
352+
generate_trait_impl,
353+
r#"
354+
struct Defaulted$0<T = i32> {}
355+
"#,
356+
r#"
357+
struct Defaulted<T = i32> {}
358+
359+
impl<T> $0 for Defaulted<T> {
360+
361+
}
362+
"#,
363+
);
364+
}
365+
366+
#[test]
367+
fn test_add_trait_impl_with_constrained_default_generic() {
368+
check_assist(
369+
generate_trait_impl,
370+
r#"
371+
struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
372+
"#,
373+
r#"
374+
struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
375+
376+
impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> $0 for Defaulted<'a, 'b, T, S> {
377+
378+
}
379+
"#,
380+
);
381+
}
382+
383+
#[test]
384+
fn test_add_trait_impl_with_const_defaulted_generic() {
385+
check_assist(
386+
generate_trait_impl,
387+
r#"
388+
struct Defaulted$0<const N: i32 = 0> {}
389+
"#,
390+
r#"
391+
struct Defaulted<const N: i32 = 0> {}
392+
393+
impl<const N: i32> $0 for Defaulted<N> {
394+
395+
}
396+
"#,
397+
);
398+
}
399+
400+
#[test]
401+
fn test_add_trait_impl_with_trait_constraint() {
402+
check_assist(
403+
generate_trait_impl,
404+
r#"
405+
pub trait Trait {}
406+
struct Struct$0<T>
407+
where
408+
T: Trait,
409+
{
410+
inner: T,
411+
}
412+
"#,
413+
r#"
414+
pub trait Trait {}
415+
struct Struct<T>
416+
where
417+
T: Trait,
418+
{
419+
inner: T,
420+
}
421+
422+
impl<T> $0 for Struct<T>
423+
where
424+
T: Trait,
425+
{
426+
427+
}
428+
"#,
429+
);
430+
}
431+
432+
#[test]
433+
fn add_trait_impl_target() {
434+
check_assist_target(
435+
generate_trait_impl,
436+
r#"
437+
struct SomeThingIrrelevant;
438+
/// Has a lifetime parameter
439+
struct Foo$0<'a, T: Foo<'a>> {}
440+
struct EvenMoreIrrelevant;
441+
"#,
442+
"/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}",
443+
);
444+
}
226445
}

0 commit comments

Comments
 (0)