]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
:arrow_up: rust-analyzer
[rust.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / generate_impl.rs
1 use syntax::ast::{self, AstNode, HasName};
2
3 use 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 // ```
24 pub(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)]
50 mod tests {
51     use crate::tests::{check_assist, check_assist_target};
52
53     use super::*;
54
55     // FIXME: break up into separate test fns
56     #[test]
57     fn test_add_impl() {
58         check_assist(
59             generate_impl,
60             "struct Foo {$0}\n",
61             "struct Foo {}\n\nimpl Foo {\n    $0\n}\n",
62         );
63         check_assist(
64             generate_impl,
65             "struct Foo<T: Clone> {$0}",
66             "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n    $0\n}",
67         );
68         check_assist(
69             generate_impl,
70             "struct Foo<'a, T: Foo<'a>> {$0}",
71             "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n    $0\n}",
72         );
73         check_assist(
74             generate_impl,
75             r#"
76             struct MyOwnArray<T, const S: usize> {}$0"#,
77             r#"
78             struct MyOwnArray<T, const S: usize> {}
79
80             impl<T, const S: usize> MyOwnArray<T, S> {
81                 $0
82             }"#,
83         );
84         check_assist(
85             generate_impl,
86             r#"
87             #[cfg(feature = "foo")]
88             struct Foo<'a, T: Foo<'a>> {$0}"#,
89             r#"
90             #[cfg(feature = "foo")]
91             struct Foo<'a, T: Foo<'a>> {}
92
93             #[cfg(feature = "foo")]
94             impl<'a, T: Foo<'a>> Foo<'a, T> {
95                 $0
96             }"#,
97         );
98
99         check_assist(
100             generate_impl,
101             r#"
102             #[cfg(not(feature = "foo"))]
103             struct Foo<'a, T: Foo<'a>> {$0}"#,
104             r#"
105             #[cfg(not(feature = "foo"))]
106             struct Foo<'a, T: Foo<'a>> {}
107
108             #[cfg(not(feature = "foo"))]
109             impl<'a, T: Foo<'a>> Foo<'a, T> {
110                 $0
111             }"#,
112         );
113
114         check_assist(
115             generate_impl,
116             r#"
117             struct Defaulted<T = i32> {}$0"#,
118             r#"
119             struct Defaulted<T = i32> {}
120
121             impl<T> Defaulted<T> {
122                 $0
123             }"#,
124         );
125
126         check_assist(
127             generate_impl,
128             r#"
129             struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}$0"#,
130             r#"
131             struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
132
133             impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> {
134                 $0
135             }"#,
136         );
137
138         check_assist(
139             generate_impl,
140             r#"
141             struct Defaulted<const N: i32 = 0> {}$0"#,
142             r#"
143             struct Defaulted<const N: i32 = 0> {}
144
145             impl<const N: i32> Defaulted<N> {
146                 $0
147             }"#,
148         );
149
150         check_assist(
151             generate_impl,
152             r#"pub trait Trait {}
153 struct Struct<T>$0
154 where
155     T: Trait,
156 {
157     inner: T,
158 }"#,
159             r#"pub trait Trait {}
160 struct Struct<T>
161 where
162     T: Trait,
163 {
164     inner: T,
165 }
166
167 impl<T> Struct<T>
168 where
169     T: Trait,
170 {
171     $0
172 }"#,
173         );
174     }
175
176     #[test]
177     fn add_impl_target() {
178         check_assist_target(
179             generate_impl,
180             "
181 struct SomeThingIrrelevant;
182 /// Has a lifetime parameter
183 struct Foo<'a, T: Foo<'a>> {$0}
184 struct EvenMoreIrrelevant;
185 ",
186             "/// Has a lifetime parameter
187 struct Foo<'a, T: Foo<'a>> {}",
188         );
189     }
190 }