]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/generate_default_from_new.rs
Generate the impl block via generate_trait_impl_text
[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 ide_db::helpers::FamousDefs;
6 use syntax::{
7     ast::{self, Impl, NameOwner},
8     AstNode,
9 };
10 use crate::utils::generate_trait_impl_text;
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         cov_mark::hit!(other_function_than_new);
47         return None;
48     }
49
50     if fn_node.param_list()?.params().next().is_some() {
51         cov_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_) {
57         cov_mark::hit!(default_block_is_already_present);
58         cov_mark::hit!(struct_in_module_with_default);
59         return None;
60     }
61
62     let insert_location = impl_.syntax().text_range();
63     let code = match ast::Struct::cast(impl_.self_ty().unwrap().syntax().clone()){
64         None => {
65             default_fn_node_for_new(impl_)
66         }
67         Some(strukt) => {
68             generate_trait_impl_text(&ast::Adt::Struct(strukt),"core:default:Default","    fn default() -> Self {{
69         Self::new()
70     }}")
71         }
72     };
73     acc.add(
74         AssistId("generate_default_from_new", crate::AssistKind::Generate),
75         "Generate a Default impl from a new fn",
76         insert_location,
77         move |builder| {
78             builder.insert(insert_location.end(), code);
79         },
80     )
81 }
82
83 fn default_fn_node_for_new(impl_: Impl) -> String {
84     format!(
85         "
86
87 impl Default for {} {{
88     fn default() -> Self {{
89         Self::new()
90     }}
91 }}",
92         impl_.self_ty().unwrap().syntax().text()
93     )
94 }
95
96 fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
97     let db = ctx.sema.db;
98     let impl_ = ctx.sema.to_def(impl_);
99     let impl_def = match impl_ {
100         Some(value) => value,
101         None => return false,
102     };
103
104     let ty = impl_def.self_ty(db);
105     let krate = impl_def.module(db).krate();
106     let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
107     let default_trait = match default {
108         Some(value) => value,
109         None => return false,
110     };
111
112     ty.impls_trait(db, default_trait, &[])
113 }
114
115 #[cfg(test)]
116 mod tests {
117     use ide_db::helpers::FamousDefs;
118
119     use crate::tests::{check_assist, check_assist_not_applicable};
120
121     use super::*;
122
123     #[test]
124     fn generate_default() {
125         check_pass(
126             r#"
127 struct Example { _inner: () }
128
129 impl Example {
130     pub fn ne$0w() -> Self {
131         Self { _inner: () }
132     }
133 }
134
135 fn main() {}
136 "#,
137             r#"
138 struct Example { _inner: () }
139
140 impl Example {
141     pub fn new() -> Self {
142         Self { _inner: () }
143     }
144 }
145
146 impl Default for Example {
147     fn default() -> Self {
148         Self::new()
149     }
150 }
151
152 fn main() {}
153 "#,
154         );
155     }
156
157     #[test]
158     fn generate_default2() {
159         check_pass(
160             r#"
161 struct Test { value: u32 }
162
163 impl Test {
164     pub fn ne$0w() -> Self {
165         Self { value: 0 }
166     }
167 }
168 "#,
169             r#"
170 struct Test { value: u32 }
171
172 impl Test {
173     pub fn new() -> Self {
174         Self { value: 0 }
175     }
176 }
177
178 impl Default for Test {
179     fn default() -> Self {
180         Self::new()
181     }
182 }
183 "#,
184         );
185     }
186
187     #[test]
188     fn generate_default3() {
189         check_pass(
190             r#"
191 pub struct Foo<T> {
192     _bar: *mut T,
193 }
194
195 impl<T> Foo<T> {
196     pub fn ne$0w() -> Self {
197         todo!()
198     }
199 }
200 "#,
201             r#"
202 pub struct Foo<T> {
203     _bar: *mut T,
204 }
205
206 impl<T> Foo<T> {
207     pub fn new() -> Self {
208         todo!()
209     }
210 }
211
212 impl<T> Default for Foo<T> {
213     fn default() -> Self {
214         Self::new()
215     }
216 }
217 "#,
218         );
219     }
220
221     #[test]
222     fn new_function_with_parameters() {
223         cov_mark::check!(new_function_with_parameters);
224         check_not_applicable(
225             r#"
226 struct Example { _inner: () }
227
228 impl Example {
229     pub fn $0new(value: ()) -> Self {
230         Self { _inner: value }
231     }
232 }
233 "#,
234         );
235     }
236
237     #[test]
238     fn other_function_than_new() {
239         cov_mark::check!(other_function_than_new);
240         check_not_applicable(
241             r#"
242 struct Example { _inner: () }
243
244 impl Example {
245     pub fn a$0dd() -> Self {
246         Self { _inner: () }
247     }
248 }
249
250 "#,
251         );
252     }
253
254     #[test]
255     fn default_block_is_already_present() {
256         cov_mark::check!(default_block_is_already_present);
257         check_not_applicable(
258             r#"
259 struct Example { _inner: () }
260
261 impl Example {
262     pub fn n$0ew() -> Self {
263         Self { _inner: () }
264     }
265 }
266
267 impl Default for Example {
268     fn default() -> Self {
269         Self::new()
270     }
271 }
272 "#,
273         );
274     }
275
276     #[test]
277     fn standalone_new_function() {
278         check_not_applicable(
279             r#"
280 fn n$0ew() -> u32 {
281     0
282 }
283 "#,
284         );
285     }
286
287     #[test]
288     fn multiple_struct_blocks() {
289         check_pass(
290             r#"
291 struct Example { _inner: () }
292 struct Test { value: u32 }
293
294 impl Example {
295     pub fn new$0() -> Self {
296         Self { _inner: () }
297     }
298 }
299 "#,
300             r#"
301 struct Example { _inner: () }
302 struct Test { value: u32 }
303
304 impl Example {
305     pub fn new() -> Self {
306         Self { _inner: () }
307     }
308 }
309
310 impl Default for Example {
311     fn default() -> Self {
312         Self::new()
313     }
314 }
315 "#,
316         );
317     }
318
319     #[test]
320     fn when_struct_is_after_impl() {
321         check_pass(
322             r#"
323 impl Example {
324     pub fn $0new() -> Self {
325         Self { _inner: () }
326     }
327 }
328
329 struct Example { _inner: () }
330 "#,
331             r#"
332 impl Example {
333     pub fn new() -> Self {
334         Self { _inner: () }
335     }
336 }
337
338 impl Default for Example {
339     fn default() -> Self {
340         Self::new()
341     }
342 }
343
344 struct Example { _inner: () }
345 "#,
346         );
347     }
348
349     #[test]
350     fn struct_in_module() {
351         check_pass(
352             r#"
353 mod test {
354     struct Example { _inner: () }
355
356     impl Example {
357         pub fn n$0ew() -> Self {
358             Self { _inner: () }
359         }
360     }
361 }
362 "#,
363             r#"
364 mod test {
365     struct Example { _inner: () }
366
367     impl Example {
368         pub fn new() -> Self {
369             Self { _inner: () }
370         }
371     }
372
373 impl Default for Example {
374     fn default() -> Self {
375         Self::new()
376     }
377 }
378 }
379 "#,
380         );
381     }
382
383     #[test]
384     fn struct_in_module_with_default() {
385         cov_mark::check!(struct_in_module_with_default);
386         check_not_applicable(
387             r#"
388 mod test {
389     struct Example { _inner: () }
390
391     impl Example {
392         pub fn n$0ew() -> Self {
393             Self { _inner: () }
394         }
395     }
396
397     impl Default for Example {
398         fn default() -> Self {
399             Self::new()
400         }
401     }
402 }
403 "#,
404         );
405     }
406
407     fn check_pass(before: &str, after: &str) {
408         let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
409         check_assist(generate_default_from_new, before, after);
410     }
411
412     fn check_not_applicable(before: &str) {
413         let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
414         check_assist_not_applicable(generate_default_from_new, before);
415     }
416 }