aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/generate_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/generate_impl.rs')
-rw-r--r--crates/ide_assists/src/handlers/generate_impl.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/generate_impl.rs b/crates/ide_assists/src/handlers/generate_impl.rs
new file mode 100644
index 000000000..a8e3c4fc2
--- /dev/null
+++ b/crates/ide_assists/src/handlers/generate_impl.rs
@@ -0,0 +1,166 @@
1use syntax::ast::{self, AstNode, NameOwner};
2
3use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
4
5// Assist: generate_impl
6//
7// Adds a new inherent impl for a type.
8//
9// ```
10// struct Ctx<T: Clone> {
11// data: T,$0
12// }
13// ```
14// ->
15// ```
16// struct Ctx<T: Clone> {
17// data: T,
18// }
19//
20// impl<T: Clone> Ctx<T> {
21// $0
22// }
23// ```
24pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
26 let name = nominal.name()?;
27 let target = nominal.syntax().text_range();
28
29 acc.add(
30 AssistId("generate_impl", AssistKind::Generate),
31 format!("Generate impl for `{}`", name),
32 target,
33 |edit| {
34 let start_offset = nominal.syntax().text_range().end();
35 match ctx.config.snippet_cap {
36 Some(cap) => {
37 let snippet = generate_impl_text(&nominal, " $0");
38 edit.insert_snippet(cap, start_offset, snippet);
39 }
40 None => {
41 let snippet = generate_impl_text(&nominal, "");
42 edit.insert(start_offset, snippet);
43 }
44 }
45 },
46 )
47}
48
49#[cfg(test)]
50mod tests {
51 use crate::tests::{check_assist, check_assist_target};
52
53 use super::*;
54
55 #[test]
56 fn test_add_impl() {
57 check_assist(
58 generate_impl,
59 "struct Foo {$0}\n",
60 "struct Foo {}\n\nimpl Foo {\n $0\n}\n",
61 );
62 check_assist(
63 generate_impl,
64 "struct Foo<T: Clone> {$0}",
65 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}",
66 );
67 check_assist(
68 generate_impl,
69 "struct Foo<'a, T: Foo<'a>> {$0}",
70 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
71 );
72 check_assist(
73 generate_impl,
74 r#"
75 #[cfg(feature = "foo")]
76 struct Foo<'a, T: Foo<'a>> {$0}"#,
77 r#"
78 #[cfg(feature = "foo")]
79 struct Foo<'a, T: Foo<'a>> {}
80
81 #[cfg(feature = "foo")]
82 impl<'a, T: Foo<'a>> Foo<'a, T> {
83 $0
84 }"#,
85 );
86
87 check_assist(
88 generate_impl,
89 r#"
90 #[cfg(not(feature = "foo"))]
91 struct Foo<'a, T: Foo<'a>> {$0}"#,
92 r#"
93 #[cfg(not(feature = "foo"))]
94 struct Foo<'a, T: Foo<'a>> {}
95
96 #[cfg(not(feature = "foo"))]
97 impl<'a, T: Foo<'a>> Foo<'a, T> {
98 $0
99 }"#,
100 );
101
102 check_assist(
103 generate_impl,
104 r#"
105 struct Defaulted<T = i32> {}$0"#,
106 r#"
107 struct Defaulted<T = i32> {}
108
109 impl<T> Defaulted<T> {
110 $0
111 }"#,
112 );
113
114 check_assist(
115 generate_impl,
116 r#"
117 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {}$0"#,
118 r#"
119 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {}
120
121 impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b> Defaulted<'a, 'b, T> {
122 $0
123 }"#,
124 );
125
126 check_assist(
127 generate_impl,
128 r#"pub trait Trait {}
129struct Struct<T>$0
130where
131 T: Trait,
132{
133 inner: T,
134}"#,
135 r#"pub trait Trait {}
136struct Struct<T>
137where
138 T: Trait,
139{
140 inner: T,
141}
142
143impl<T> Struct<T>
144where
145 T: Trait,
146{
147 $0
148}"#,
149 );
150 }
151
152 #[test]
153 fn add_impl_target() {
154 check_assist_target(
155 generate_impl,
156 "
157struct SomeThingIrrelevant;
158/// Has a lifetime parameter
159struct Foo<'a, T: Foo<'a>> {$0}
160struct EvenMoreIrrelevant;
161",
162 "/// Has a lifetime parameter
163struct Foo<'a, T: Foo<'a>> {}",
164 );
165 }
166}