aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-16 20:32:40 +0100
committerGitHub <[email protected]>2021-05-16 20:32:40 +0100
commitb82458818d44dfe5b4b5db38d8113e3f3194506e (patch)
tree411b4b565105fe1abc33096c56a0bf4316bf49ce /crates/ide_assists
parentef6df1d994394e5f2097edfa12d0489762903099 (diff)
parentf5ea2a2ab0df1a8ccf9f20d97ca07f9169e70c79 (diff)
Merge #8845
8845: Generate the impl block via generate_trait_impl_text_from_impl r=Veykril a=hi-rustin Try to close https://github.com/rust-analyzer/rust-analyzer/issues/8827 Co-authored-by: hi-rustin <[email protected]>
Diffstat (limited to 'crates/ide_assists')
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs287
1 files changed, 275 insertions, 12 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 dc14552d6..bad826366 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -3,8 +3,10 @@ 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, GenericParamsOwner, Impl, NameOwner, TypeBoundsOwner},
8 AstNode, 10 AstNode,
9}; 11};
10 12
@@ -65,23 +67,56 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext)
65 "Generate a Default impl from a new fn", 67 "Generate a Default impl from a new fn",
66 insert_location, 68 insert_location,
67 move |builder| { 69 move |builder| {
68 let code = default_fn_node_for_new(impl_); 70 let default_code = " fn default() -> Self {
71 Self::new()
72 }";
73 let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
69 builder.insert(insert_location.end(), code); 74 builder.insert(insert_location.end(), code);
70 }, 75 },
71 ) 76 )
72} 77}
73 78
74fn default_fn_node_for_new(impl_: Impl) -> String { 79fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
75 format!( 80 let generic_params = impl_.generic_param_list();
76 " 81 let mut buf = String::with_capacity(code.len());
82 buf.push_str("\n\n");
83 buf.push_str("impl");
84
85 if let Some(generic_params) = &generic_params {
86 let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
87 let type_params = generic_params.type_params().map(|type_param| {
88 let mut buf = String::new();
89 if let Some(it) = type_param.name() {
90 format_to!(buf, "{}", it.syntax());
91 }
92 if let Some(it) = type_param.colon_token() {
93 format_to!(buf, "{} ", it);
94 }
95 if let Some(it) = type_param.type_bound_list() {
96 format_to!(buf, "{}", it.syntax());
97 }
98 buf
99 });
100 let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
101 let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
102 format_to!(buf, "<{}>", generics);
103 }
104
105 buf.push(' ');
106 buf.push_str(trait_text);
107 buf.push_str(" for ");
108 buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string());
109
110 match impl_.where_clause() {
111 Some(where_clause) => {
112 format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
113 }
114 None => {
115 format_to!(buf, " {{\n{}\n}}", code);
116 }
117 }
77 118
78impl Default for {} {{ 119 buf
79 fn default() -> Self {{
80 Self::new()
81 }}
82}}",
83 impl_.self_ty().unwrap().syntax().text()
84 )
85} 120}
86 121
87fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { 122fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
@@ -176,6 +211,234 @@ impl Default for Test {
176 } 211 }
177 212
178 #[test] 213 #[test]
214 fn new_function_with_generic() {
215 check_pass(
216 r#"
217pub struct Foo<T> {
218 _bar: *mut T,
219}
220
221impl<T> Foo<T> {
222 pub fn ne$0w() -> Self {
223 unimplemented!()
224 }
225}
226"#,
227 r#"
228pub struct Foo<T> {
229 _bar: *mut T,
230}
231
232impl<T> Foo<T> {
233 pub fn new() -> Self {
234 unimplemented!()
235 }
236}
237
238impl<T> Default for Foo<T> {
239 fn default() -> Self {
240 Self::new()
241 }
242}
243"#,
244 );
245 }
246
247 #[test]
248 fn new_function_with_generics() {
249 check_pass(
250 r#"
251pub struct Foo<T, B> {
252 _tars: *mut T,
253 _bar: *mut B,
254}
255
256impl<T, B> Foo<T, B> {
257 pub fn ne$0w() -> Self {
258 unimplemented!()
259 }
260}
261"#,
262 r#"
263pub struct Foo<T, B> {
264 _tars: *mut T,
265 _bar: *mut B,
266}
267
268impl<T, B> Foo<T, B> {
269 pub fn new() -> Self {
270 unimplemented!()
271 }
272}
273
274impl<T, B> Default for Foo<T, B> {
275 fn default() -> Self {
276 Self::new()
277 }
278}
279"#,
280 );
281 }
282
283 #[test]
284 fn new_function_with_generic_and_bound() {
285 check_pass(
286 r#"
287pub struct Foo<T> {
288 t: T,
289}
290
291impl<T: From<i32>> Foo<T> {
292 pub fn ne$0w() -> Self {
293 Foo { t: 0.into() }
294 }
295}
296"#,
297 r#"
298pub struct Foo<T> {
299 t: T,
300}
301
302impl<T: From<i32>> Foo<T> {
303 pub fn new() -> Self {
304 Foo { t: 0.into() }
305 }
306}
307
308impl<T: From<i32>> Default for Foo<T> {
309 fn default() -> Self {
310 Self::new()
311 }
312}
313"#,
314 );
315 }
316
317 #[test]
318 fn new_function_with_generics_and_bounds() {
319 check_pass(
320 r#"
321pub struct Foo<T, B> {
322 _tars: T,
323 _bar: B,
324}
325
326impl<T: From<i32>, B: From<i64>> Foo<T, B> {
327 pub fn ne$0w() -> Self {
328 unimplemented!()
329 }
330}
331"#,
332 r#"
333pub struct Foo<T, B> {
334 _tars: T,
335 _bar: B,
336}
337
338impl<T: From<i32>, B: From<i64>> Foo<T, B> {
339 pub fn new() -> Self {
340 unimplemented!()
341 }
342}
343
344impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
345 fn default() -> Self {
346 Self::new()
347 }
348}
349"#,
350 );
351 }
352
353 #[test]
354 fn new_function_with_generic_and_where() {
355 check_pass(
356 r#"
357pub struct Foo<T> {
358 t: T,
359}
360
361impl<T: From<i32>> Foo<T>
362where
363 Option<T>: Debug
364{
365 pub fn ne$0w() -> Self {
366 Foo { t: 0.into() }
367 }
368}
369"#,
370 r#"
371pub struct Foo<T> {
372 t: T,
373}
374
375impl<T: From<i32>> Foo<T>
376where
377 Option<T>: Debug
378{
379 pub fn new() -> Self {
380 Foo { t: 0.into() }
381 }
382}
383
384impl<T: From<i32>> Default for Foo<T>
385where
386 Option<T>: Debug
387{
388 fn default() -> Self {
389 Self::new()
390 }
391}
392"#,
393 );
394 }
395
396 #[test]
397 fn new_function_with_generics_and_wheres() {
398 check_pass(
399 r#"
400pub struct Foo<T, B> {
401 _tars: T,
402 _bar: B,
403}
404
405impl<T: From<i32>, B: From<i64>> Foo<T, B>
406where
407 Option<T>: Debug, Option<B>: Debug,
408{
409 pub fn ne$0w() -> Self {
410 unimplemented!()
411 }
412}
413"#,
414 r#"
415pub struct Foo<T, B> {
416 _tars: T,
417 _bar: B,
418}
419
420impl<T: From<i32>, B: From<i64>> Foo<T, B>
421where
422 Option<T>: Debug, Option<B>: Debug,
423{
424 pub fn new() -> Self {
425 unimplemented!()
426 }
427}
428
429impl<T: From<i32>, B: From<i64>> Default for Foo<T, B>
430where
431 Option<T>: Debug, Option<B>: Debug,
432{
433 fn default() -> Self {
434 Self::new()
435 }
436}
437"#,
438 );
439 }
440
441 #[test]
179 fn new_function_with_parameters() { 442 fn new_function_with_parameters() {
180 cov_mark::check!(new_function_with_parameters); 443 cov_mark::check!(new_function_with_parameters);
181 check_not_applicable( 444 check_not_applicable(