aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/generate_default_from_new.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/generate_default_from_new.rs')
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs274
1 files changed, 249 insertions, 25 deletions
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index 374611fbf..f301932ad 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -3,11 +3,12 @@ use crate::{
3 AssistId, 3 AssistId,
4}; 4};
5use ide_db::helpers::FamousDefs; 5use ide_db::helpers::FamousDefs;
6use itertools::Itertools;
7use stdx::format_to;
6use syntax::{ 8use syntax::{
7 ast::{self, Impl, NameOwner}, 9 ast::{self, AttrsOwner, GenericParamsOwner, Impl, NameOwner, TypeBoundsOwner},
8 AstNode, 10 AstNode,
9}; 11};
10use crate::utils::generate_trait_impl_text;
11 12
12// Assist: generate_default_from_new 13// Assist: generate_default_from_new
13// 14//
@@ -60,37 +61,66 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext)
60 } 61 }
61 62
62 let insert_location = impl_.syntax().text_range(); 63 let insert_location = impl_.syntax().text_range();
63 let code = match ast::Struct::cast(impl_.self_ty().unwrap().syntax().clone()){ 64
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( 65 acc.add(
74 AssistId("generate_default_from_new", crate::AssistKind::Generate), 66 AssistId("generate_default_from_new", crate::AssistKind::Generate),
75 "Generate a Default impl from a new fn", 67 "Generate a Default impl from a new fn",
76 insert_location, 68 insert_location,
77 move |builder| { 69 move |builder| {
70 let default_code = " fn default() -> Self {
71 Self::new()
72 }";
73 let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
78 builder.insert(insert_location.end(), code); 74 builder.insert(insert_location.end(), code);
79 }, 75 },
80 ) 76 )
81} 77}
82 78
83fn default_fn_node_for_new(impl_: Impl) -> String { 79fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
84 format!( 80 let generic_params = impl_.generic_param_list();
85 " 81 let mut buf = String::with_capacity(code.len());
82 buf.push_str("\n\n");
83 impl_
84 .attrs()
85 .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
86 .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
87 buf.push_str("impl");
88
89 if let Some(generic_params) = &generic_params {
90 let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
91 let type_params = generic_params.type_params().map(|type_param| {
92 let mut buf = String::new();
93 if let Some(it) = type_param.name() {
94 format_to!(buf, "{}", it.syntax());
95 }
96 if let Some(it) = type_param.colon_token() {
97 format_to!(buf, "{} ", it);
98 }
99 if let Some(it) = type_param.type_bound_list() {
100 format_to!(buf, "{}", it.syntax());
101 }
102 buf
103 });
104 let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
105 let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
106 format_to!(buf, "<{}>", generics);
107 }
108
109 buf.push(' ');
110 buf.push_str(trait_text);
111 buf.push_str(" for ");
112 buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string());
113
114 match impl_.where_clause() {
115 Some(where_clause) => {
116 format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
117 }
118 None => {
119 format_to!(buf, " {{\n{}\n}}", code);
120 }
121 }
86 122
87impl Default for {} {{ 123 buf
88 fn default() -> Self {{
89 Self::new()
90 }}
91}}",
92 impl_.self_ty().unwrap().syntax().text()
93 )
94} 124}
95 125
96fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { 126fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
@@ -185,7 +215,7 @@ impl Default for Test {
185 } 215 }
186 216
187 #[test] 217 #[test]
188 fn generate_default3() { 218 fn new_function_with_generic() {
189 check_pass( 219 check_pass(
190 r#" 220 r#"
191pub struct Foo<T> { 221pub struct Foo<T> {
@@ -194,7 +224,7 @@ pub struct Foo<T> {
194 224
195impl<T> Foo<T> { 225impl<T> Foo<T> {
196 pub fn ne$0w() -> Self { 226 pub fn ne$0w() -> Self {
197 todo!() 227 unimplemented!()
198 } 228 }
199} 229}
200"#, 230"#,
@@ -205,7 +235,7 @@ pub struct Foo<T> {
205 235
206impl<T> Foo<T> { 236impl<T> Foo<T> {
207 pub fn new() -> Self { 237 pub fn new() -> Self {
208 todo!() 238 unimplemented!()
209 } 239 }
210} 240}
211 241
@@ -219,6 +249,200 @@ impl<T> Default for Foo<T> {
219 } 249 }
220 250
221 #[test] 251 #[test]
252 fn new_function_with_generics() {
253 check_pass(
254 r#"
255pub struct Foo<T, B> {
256 _tars: *mut T,
257 _bar: *mut B,
258}
259
260impl<T, B> Foo<T, B> {
261 pub fn ne$0w() -> Self {
262 unimplemented!()
263 }
264}
265"#,
266 r#"
267pub struct Foo<T, B> {
268 _tars: *mut T,
269 _bar: *mut B,
270}
271
272impl<T, B> Foo<T, B> {
273 pub fn new() -> Self {
274 unimplemented!()
275 }
276}
277
278impl<T, B> Default for Foo<T, B> {
279 fn default() -> Self {
280 Self::new()
281 }
282}
283"#,
284 );
285 }
286
287 #[test]
288 fn new_function_with_generic_and_bound() {
289 check_pass(
290 r#"
291pub struct Foo<T> {
292 t: T,
293}
294
295impl<T: From<i32>> Foo<T> {
296 pub fn ne$0w() -> Self {
297 Foo { t: 0.into() }
298 }
299}
300"#,
301 r#"
302pub struct Foo<T> {
303 t: T,
304}
305
306impl<T: From<i32>> Foo<T> {
307 pub fn new() -> Self {
308 Foo { t: 0.into() }
309 }
310}
311
312impl<T: From<i32>> Default for Foo<T> {
313 fn default() -> Self {
314 Self::new()
315 }
316}
317"#,
318 );
319 }
320
321 #[test]
322 fn new_function_with_generics_and_bounds() {
323 check_pass(
324 r#"
325pub struct Foo<T, B> {
326 _tars: T,
327 _bar: B,
328}
329
330impl<T: From<i32>, B: From<i64>> Foo<T, B> {
331 pub fn ne$0w() -> Self {
332 unimplemented!()
333 }
334}
335"#,
336 r#"
337pub struct Foo<T, B> {
338 _tars: T,
339 _bar: B,
340}
341
342impl<T: From<i32>, B: From<i64>> Foo<T, B> {
343 pub fn new() -> Self {
344 unimplemented!()
345 }
346}
347
348impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
349 fn default() -> Self {
350 Self::new()
351 }
352}
353"#,
354 );
355 }
356
357 #[test]
358 fn new_function_with_generic_and_where() {
359 check_pass(
360 r#"
361pub struct Foo<T> {
362 t: T,
363}
364
365impl<T: From<i32>> Foo<T>
366where
367 Option<T>: Debug
368{
369 pub fn ne$0w() -> Self {
370 Foo { t: 0.into() }
371 }
372}
373"#,
374 r#"
375pub struct Foo<T> {
376 t: T,
377}
378
379impl<T: From<i32>> Foo<T>
380where
381 Option<T>: Debug
382{
383 pub fn new() -> Self {
384 Foo { t: 0.into() }
385 }
386}
387
388impl<T: From<i32>> Default for Foo<T>
389where
390 Option<T>: Debug
391{
392 fn default() -> Self {
393 Self::new()
394 }
395}
396"#,
397 );
398 }
399
400 #[test]
401 fn new_function_with_generics_and_wheres() {
402 check_pass(
403 r#"
404pub struct Foo<T, B> {
405 _tars: T,
406 _bar: B,
407}
408
409impl<T: From<i32>, B: From<i64>> Foo<T, B>
410where
411 Option<T>: Debug, Option<B>: Debug,
412{
413 pub fn ne$0w() -> Self {
414 unimplemented!()
415 }
416}
417"#,
418 r#"
419pub struct Foo<T, B> {
420 _tars: T,
421 _bar: B,
422}
423
424impl<T: From<i32>, B: From<i64>> Foo<T, B>
425where
426 Option<T>: Debug, Option<B>: Debug,
427{
428 pub fn new() -> Self {
429 unimplemented!()
430 }
431}
432
433impl<T: From<i32>, B: From<i64>> Default for Foo<T, B>
434where
435 Option<T>: Debug, Option<B>: Debug,
436{
437 fn default() -> Self {
438 Self::new()
439 }
440}
441"#,
442 );
443 }
444
445 #[test]
222 fn new_function_with_parameters() { 446 fn new_function_with_parameters() {
223 cov_mark::check!(new_function_with_parameters); 447 cov_mark::check!(new_function_with_parameters);
224 check_not_applicable( 448 check_not_applicable(