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