]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/generate_default_from_new.rs
7708: Added the logic to check is default impl is already present.
[rust.git] / crates / ide_assists / src / handlers / generate_default_from_new.rs
1 use crate::{
2     assist_context::{AssistContext, Assists},
3     AssistId,
4 };
5 use hir::TypeRef;
6 use syntax::{
7     ast::{self, Impl, NameOwner},
8     AstNode,
9 };
10 use test_utils::mark;
11
12 // Assist: generate_default_from_new
13 //
14 // Generates default implementation from new method.
15 //
16 // ```
17 // struct Example { _inner: () }
18 //
19 // impl Example {
20 //     pub fn n$0ew() -> Self {
21 //         Self { _inner: () }
22 //     }
23 // }
24 // ```
25 // ->
26 // ```
27 // struct Example { _inner: () }
28 //
29 // impl Example {
30 //     pub fn new() -> Self {
31 //         Self { _inner: () }
32 //     }
33 // }
34 //
35 // impl Default for Example {
36 //     fn default() -> Self {
37 //         Self::new()
38 //     }
39 // }
40 // ```
41 pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
42     let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
43     let fn_name = fn_node.name()?;
44
45     if fn_name.text() != "new" {
46         mark::hit!(other_function_than_new);
47         return None;
48     }
49
50     if fn_node.param_list()?.params().next().is_some() {
51         mark::hit!(new_function_with_parameters);
52         return None;
53     }
54
55     let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
56     if is_default_implemented(ctx, &impl_).is_some() {
57         return None;
58     }
59
60     let insert_location = impl_.syntax().text_range();
61
62     acc.add(
63         AssistId("generate_default_from_new", crate::AssistKind::Generate),
64         "Generate a Default impl from a new fn",
65         insert_location,
66         move |builder| {
67             let code = default_fn_node_for_new(impl_);
68             builder.insert(insert_location.end(), code);
69         },
70     )
71 }
72
73 fn default_fn_node_for_new(impl_: Impl) -> String {
74     format!(
75         "
76
77 impl Default for {} {{
78     fn default() -> Self {{
79         Self::new()
80     }}
81 }}",
82         impl_.self_ty().unwrap().syntax().text()
83     )
84 }
85
86 fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> Option<bool> {
87     let db = ctx.sema.db;
88     let module = impl_.syntax().parent()?;
89     let sema_scope = ctx.sema.scope(&module);
90     let impls = sema_scope.module()?.impl_defs(db);
91     let mut name = None;
92     for i in impls {
93         if let Some(TypeRef::Path(p)) = i.target_trait(db) {
94             name = p.segments().iter().map(|s| s.name.to_string()).find(|n| n == "Default");
95         }
96     }
97
98     name.map(|n| !n.is_empty())
99 }
100
101 #[cfg(test)]
102 mod tests {
103     use crate::tests::{check_assist, check_assist_not_applicable};
104
105     use super::*;
106
107     #[test]
108     fn generate_default() {
109         check_assist(
110             generate_default_from_new,
111             r#"
112 struct Example { _inner: () }
113
114 impl Example {
115     pub fn ne$0w() -> Self {
116         Self { _inner: () }
117     }
118 }
119
120 fn main() {}
121 "#,
122             r#"
123 struct Example { _inner: () }
124
125 impl Example {
126     pub fn new() -> Self {
127         Self { _inner: () }
128     }
129 }
130
131 impl Default for Example {
132     fn default() -> Self {
133         Self::new()
134     }
135 }
136
137 fn main() {}
138 "#,
139         );
140     }
141
142     #[test]
143     fn generate_default2() {
144         check_assist(
145             generate_default_from_new,
146             r#"
147 struct Test { value: u32 }
148
149 impl Test {
150     pub fn ne$0w() -> Self {
151         Self { value: 0 }
152     }
153 }
154 "#,
155             r#"
156 struct Test { value: u32 }
157
158 impl Test {
159     pub fn new() -> Self {
160         Self { value: 0 }
161     }
162 }
163
164 impl Default for Test {
165     fn default() -> Self {
166         Self::new()
167     }
168 }
169 "#,
170         );
171     }
172
173     #[test]
174     fn new_function_with_parameters() {
175         mark::check!(new_function_with_parameters);
176         check_assist_not_applicable(
177             generate_default_from_new,
178             r#"
179 struct Example { _inner: () }
180
181 impl Example {
182     pub fn $0new(value: ()) -> Self {
183         Self { _inner: value }
184     }
185 }
186 "#,
187         );
188     }
189
190     #[test]
191     fn other_function_than_new() {
192         mark::check!(other_function_than_new);
193         check_assist_not_applicable(
194             generate_default_from_new,
195             r#"
196 struct Example { _inner: () }
197
198 impl Exmaple {
199     pub fn a$0dd() -> Self {
200         Self { _inner: () }
201     }
202 }
203
204 "#,
205         );
206     }
207
208     #[test]
209     fn default_block_is_already_present() {
210         check_assist_not_applicable(
211             generate_default_from_new,
212             r#"
213 struct Example { _inner: () }
214
215 impl Exmaple {
216     pub fn n$0ew() -> Self {
217         Self { _inner: () }
218     }
219 }
220
221 impl Default for Example {
222     fn default() -> Self {
223         Self::new()
224     }
225 }
226 "#,
227         );
228     }
229
230     #[test]
231     fn standalone_new_function() {
232         check_assist_not_applicable(
233             generate_default_from_new,
234             r#"
235 fn n$0ew() -> u32 {
236     0
237 }
238 "#,
239         );
240     }
241
242     #[test]
243     fn multiple_struct_blocks() {
244         check_assist(
245             generate_default_from_new,
246             r#"
247 struct Example { _inner: () }
248 struct Test { value: u32 }
249
250 impl Example {
251     pub fn new$0() -> Self {
252         Self { _inner: () }
253     }
254 }
255 "#,
256             r#"
257 struct Example { _inner: () }
258 struct Test { value: u32 }
259
260 impl Example {
261     pub fn new() -> Self {
262         Self { _inner: () }
263     }
264 }
265
266 impl Default for Example {
267     fn default() -> Self {
268         Self::new()
269     }
270 }
271 "#,
272         );
273     }
274
275     #[test]
276     fn when_struct_is_after_impl() {
277         check_assist(
278             generate_default_from_new,
279             r#"
280 impl Example {
281     pub fn $0new() -> Self {
282         Self { _inner: () }
283     }
284 }
285
286 struct Example { _inner: () }
287 "#,
288             r#"
289 impl Example {
290     pub fn new() -> Self {
291         Self { _inner: () }
292     }
293 }
294
295 impl Default for Example {
296     fn default() -> Self {
297         Self::new()
298     }
299 }
300
301 struct Example { _inner: () }
302 "#,
303         );
304     }
305
306     #[test]
307     fn struct_in_module() {
308         check_assist(
309             generate_default_from_new,
310             r#"
311 mod test {
312     struct Example { _inner: () }
313
314     impl Example {
315         pub fn n$0ew() -> Self {
316             Self { _inner: () }
317         }
318     }
319 }
320 "#,
321             r#"
322 mod test {
323     struct Example { _inner: () }
324
325     impl Example {
326         pub fn new() -> Self {
327             Self { _inner: () }
328         }
329     }
330
331 impl Default for Example {
332     fn default() -> Self {
333         Self::new()
334     }
335 }
336 }
337 "#,
338         );
339     }
340
341     #[test]
342     fn struct_in_module_with_default() {
343         check_assist_not_applicable(
344             generate_default_from_new,
345             r#"
346 mod test {
347     struct Example { _inner: () }
348
349     impl Example {
350         pub fn n$0ew() -> Self {
351             Self { _inner: () }
352         }
353     }
354
355     impl Default for Example {
356         fn default() -> Self {
357             Self::new()
358         }
359     }
360 }
361 "#,
362         );
363     }
364 }