aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/src/handlers/generate_from_impl_for_enum.rs131
-rw-r--r--crates/assists/src/handlers/generate_getter.rs8
-rw-r--r--crates/assists/src/handlers/generate_getter_mut.rs8
-rw-r--r--crates/assists/src/handlers/generate_impl.rs70
-rw-r--r--crates/assists/src/handlers/generate_setter.rs8
-rw-r--r--crates/assists/src/handlers/replace_derive_with_manual_impl.rs26
-rw-r--r--crates/assists/src/tests/generated.rs2
-rw-r--r--crates/assists/src/utils.rs52
8 files changed, 200 insertions, 105 deletions
diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
index d9af6ab11..d9388a737 100644
--- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
@@ -3,7 +3,7 @@ use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
7 7
8// Assist: generate_from_impl_for_enum 8// Assist: generate_from_impl_for_enum
9// 9//
@@ -18,25 +18,29 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
18// 18//
19// impl From<u32> for A { 19// impl From<u32> for A {
20// fn from(v: u32) -> Self { 20// fn from(v: u32) -> Self {
21// A::One(v) 21// Self::One(v)
22// } 22// }
23// } 23// }
24// ``` 24// ```
25pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let variant = ctx.find_node_at_offset::<ast::Variant>()?; 26 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
27 let variant_name = variant.name()?; 27 let variant_name = variant.name()?;
28 let enum_name = variant.parent_enum().name()?; 28 let enum_ = ast::Adt::Enum(variant.parent_enum());
29 let field_list = match variant.kind() { 29 let (field_name, field_type) = match variant.kind() {
30 ast::StructKind::Tuple(field_list) => field_list, 30 ast::StructKind::Tuple(field_list) => {
31 _ => return None, 31 if field_list.fields().count() != 1 {
32 }; 32 return None;
33 if field_list.fields().count() != 1 { 33 }
34 return None; 34 (None, field_list.fields().next()?.ty()?)
35 } 35 }
36 let field_type = field_list.fields().next()?.ty()?; 36 ast::StructKind::Record(field_list) => {
37 let path = match field_type { 37 if field_list.fields().count() != 1 {
38 ast::Type::PathType(it) => it, 38 return None;
39 _ => return None, 39 }
40 let field = field_list.fields().next()?;
41 (Some(field.name()?), field.ty()?)
42 }
43 ast::StructKind::Unit => return None,
40 }; 44 };
41 45
42 if existing_from_impl(&ctx.sema, &variant).is_some() { 46 if existing_from_impl(&ctx.sema, &variant).is_some() {
@@ -51,19 +55,27 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext
51 target, 55 target,
52 |edit| { 56 |edit| {
53 let start_offset = variant.parent_enum().syntax().text_range().end(); 57 let start_offset = variant.parent_enum().syntax().text_range().end();
54 let buf = format!( 58 let from_trait = format!("From<{}>", field_type.syntax());
55 r#" 59 let impl_code = if let Some(name) = field_name {
56 60 format!(
57impl From<{0}> for {1} {{ 61 r#" fn from({0}: {1}) -> Self {{
58 fn from(v: {0}) -> Self {{ 62 Self::{2} {{ {0} }}
59 {1}::{2}(v) 63 }}"#,
60 }} 64 name.text(),
61}}"#, 65 field_type.syntax(),
62 path.syntax(), 66 variant_name,
63 enum_name, 67 )
64 variant_name 68 } else {
65 ); 69 format!(
66 edit.insert(start_offset, buf); 70 r#" fn from(v: {}) -> Self {{
71 Self::{}(v)
72 }}"#,
73 field_type.syntax(),
74 variant_name,
75 )
76 };
77 let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
78 edit.insert(start_offset, from_impl);
67 }, 79 },
68 ) 80 )
69} 81}
@@ -106,7 +118,7 @@ mod tests {
106 118
107impl From<u32> for A { 119impl From<u32> for A {
108 fn from(v: u32) -> Self { 120 fn from(v: u32) -> Self {
109 A::One(v) 121 Self::One(v)
110 } 122 }
111}"#, 123}"#,
112 ); 124 );
@@ -121,7 +133,7 @@ impl From<u32> for A {
121 133
122impl From<foo::bar::baz::Boo> for A { 134impl From<foo::bar::baz::Boo> for A {
123 fn from(v: foo::bar::baz::Boo) -> Self { 135 fn from(v: foo::bar::baz::Boo) -> Self {
124 A::One(v) 136 Self::One(v)
125 } 137 }
126}"#, 138}"#,
127 ); 139 );
@@ -145,7 +157,17 @@ impl From<foo::bar::baz::Boo> for A {
145 157
146 #[test] 158 #[test]
147 fn test_add_from_impl_struct_variant() { 159 fn test_add_from_impl_struct_variant() {
148 check_not_applicable("enum A { $0One { x: u32 } }"); 160 check_assist(
161 generate_from_impl_for_enum,
162 "enum A { $0One { x: u32 } }",
163 r#"enum A { One { x: u32 } }
164
165impl From<u32> for A {
166 fn from(x: u32) -> Self {
167 Self::One { x }
168 }
169}"#,
170 );
149 } 171 }
150 172
151 #[test] 173 #[test]
@@ -157,7 +179,7 @@ enum A { $0One(u32), }
157 179
158impl From<u32> for A { 180impl From<u32> for A {
159 fn from(v: u32) -> Self { 181 fn from(v: u32) -> Self {
160 A::One(v) 182 Self::One(v)
161 } 183 }
162} 184}
163"#, 185"#,
@@ -183,7 +205,7 @@ pub trait From<T> {
183 205
184impl From<u32> for A { 206impl From<u32> for A {
185 fn from(v: u32) -> Self { 207 fn from(v: u32) -> Self {
186 A::One(v) 208 Self::One(v)
187 } 209 }
188} 210}
189 211
@@ -198,4 +220,49 @@ pub trait From<T> {
198}"#, 220}"#,
199 ); 221 );
200 } 222 }
223
224 #[test]
225 fn test_add_from_impl_static_str() {
226 check_assist(
227 generate_from_impl_for_enum,
228 "enum A { $0One(&'static str) }",
229 r#"enum A { One(&'static str) }
230
231impl From<&'static str> for A {
232 fn from(v: &'static str) -> Self {
233 Self::One(v)
234 }
235}"#,
236 );
237 }
238
239 #[test]
240 fn test_add_from_impl_generic_enum() {
241 check_assist(
242 generate_from_impl_for_enum,
243 "enum Generic<T, U: Clone> { $0One(T), Two(U) }",
244 r#"enum Generic<T, U: Clone> { One(T), Two(U) }
245
246impl<T, U: Clone> From<T> for Generic<T, U> {
247 fn from(v: T) -> Self {
248 Self::One(v)
249 }
250}"#,
251 );
252 }
253
254 #[test]
255 fn test_add_from_impl_with_lifetime() {
256 check_assist(
257 generate_from_impl_for_enum,
258 "enum Generic<'a> { $0One(&'a i32) }",
259 r#"enum Generic<'a> { One(&'a i32) }
260
261impl<'a> From<&'a i32> for Generic<'a> {
262 fn from(v: &'a i32) -> Self {
263 Self::One(v)
264 }
265}"#,
266 );
267 }
201} 268}
diff --git a/crates/assists/src/handlers/generate_getter.rs b/crates/assists/src/handlers/generate_getter.rs
index fbcf8b069..df7d1bb95 100644
--- a/crates/assists/src/handlers/generate_getter.rs
+++ b/crates/assists/src/handlers/generate_getter.rs
@@ -1,10 +1,9 @@
1use stdx::{format_to, to_lower_snake_case}; 1use stdx::{format_to, to_lower_snake_case};
2use syntax::ast::VisibilityOwner; 2use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
3use syntax::ast::{self, AstNode, NameOwner};
4 3
5use crate::{ 4use crate::{
6 utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, 5 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
7 AssistContext, AssistId, AssistKind, Assists, 6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
8}; 7};
9 8
10// Assist: generate_getter 9// Assist: generate_getter
@@ -42,7 +41,8 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
42 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; 41 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?;
43 42
44 let target = field.syntax().text_range(); 43 let target = field.syntax().text_range();
45 acc.add( 44 acc.add_group(
45 &GroupLabel("Generate getter/setter".to_owned()),
46 AssistId("generate_getter", AssistKind::Generate), 46 AssistId("generate_getter", AssistKind::Generate),
47 "Generate a getter method", 47 "Generate a getter method",
48 target, 48 target,
diff --git a/crates/assists/src/handlers/generate_getter_mut.rs b/crates/assists/src/handlers/generate_getter_mut.rs
index bf0d99881..821c2eed5 100644
--- a/crates/assists/src/handlers/generate_getter_mut.rs
+++ b/crates/assists/src/handlers/generate_getter_mut.rs
@@ -1,10 +1,9 @@
1use stdx::{format_to, to_lower_snake_case}; 1use stdx::{format_to, to_lower_snake_case};
2use syntax::ast::VisibilityOwner; 2use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
3use syntax::ast::{self, AstNode, NameOwner};
4 3
5use crate::{ 4use crate::{
6 utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, 5 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
7 AssistContext, AssistId, AssistKind, Assists, 6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
8}; 7};
9 8
10// Assist: generate_getter_mut 9// Assist: generate_getter_mut
@@ -46,7 +45,8 @@ pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Opt
46 )?; 45 )?;
47 46
48 let target = field.syntax().text_range(); 47 let target = field.syntax().text_range();
49 acc.add( 48 acc.add_group(
49 &GroupLabel("Generate getter/setter".to_owned()),
50 AssistId("generate_getter_mut", AssistKind::Generate), 50 AssistId("generate_getter_mut", AssistKind::Generate),
51 "Generate a mut getter method", 51 "Generate a mut getter method",
52 target, 52 target,
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs
index 61d1bd25c..16a600e6f 100644
--- a/crates/assists/src/handlers/generate_impl.rs
+++ b/crates/assists/src/handlers/generate_impl.rs
@@ -1,11 +1,6 @@
1use itertools::Itertools; 1use syntax::ast::{self, AstNode, NameOwner};
2use stdx::format_to;
3use syntax::{
4 ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
5 SmolStr,
6};
7 2
8use crate::{AssistContext, AssistId, AssistKind, Assists}; 3use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
9 4
10// Assist: generate_impl 5// Assist: generate_impl
11// 6//
@@ -36,44 +31,15 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
36 format!("Generate impl for `{}`", name), 31 format!("Generate impl for `{}`", name),
37 target, 32 target,
38 |edit| { 33 |edit| {
39 let type_params = nominal.generic_param_list();
40 let start_offset = nominal.syntax().text_range().end(); 34 let start_offset = nominal.syntax().text_range().end();
41 let mut buf = String::new();
42 buf.push_str("\n\n");
43 nominal
44 .attrs()
45 .filter(|attr| {
46 attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)
47 })
48 .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
49
50 buf.push_str("impl");
51 if let Some(type_params) = &type_params {
52 format_to!(buf, "{}", type_params.syntax());
53 }
54 buf.push_str(" ");
55 buf.push_str(name.text());
56 if let Some(type_params) = type_params {
57 let lifetime_params = type_params
58 .lifetime_params()
59 .filter_map(|it| it.lifetime())
60 .map(|it| SmolStr::from(it.text()));
61 let type_params = type_params
62 .type_params()
63 .filter_map(|it| it.name())
64 .map(|it| SmolStr::from(it.text()));
65
66 let generic_params = lifetime_params.chain(type_params).format(", ");
67 format_to!(buf, "<{}>", generic_params)
68 }
69 match ctx.config.snippet_cap { 35 match ctx.config.snippet_cap {
70 Some(cap) => { 36 Some(cap) => {
71 buf.push_str(" {\n $0\n}"); 37 let snippet = generate_impl_text(&nominal, " $0");
72 edit.insert_snippet(cap, start_offset, buf); 38 edit.insert_snippet(cap, start_offset, snippet);
73 } 39 }
74 None => { 40 None => {
75 buf.push_str(" {\n}"); 41 let snippet = generate_impl_text(&nominal, "");
76 edit.insert(start_offset, buf); 42 edit.insert(start_offset, snippet);
77 } 43 }
78 } 44 }
79 }, 45 },
@@ -132,6 +98,30 @@ mod tests {
132 $0 98 $0
133 }"#, 99 }"#,
134 ); 100 );
101
102 check_assist(
103 generate_impl,
104 r#"
105 struct Defaulted<T = i32> {}$0"#,
106 r#"
107 struct Defaulted<T = i32> {}
108
109 impl<T> Defaulted<T> {
110 $0
111 }"#,
112 );
113
114 check_assist(
115 generate_impl,
116 r#"
117 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {}$0"#,
118 r#"
119 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String> {}
120
121 impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b> Defaulted<'a, 'b, T> {
122 $0
123 }"#,
124 );
135 } 125 }
136 126
137 #[test] 127 #[test]
diff --git a/crates/assists/src/handlers/generate_setter.rs b/crates/assists/src/handlers/generate_setter.rs
index b655f9b9c..288cf745d 100644
--- a/crates/assists/src/handlers/generate_setter.rs
+++ b/crates/assists/src/handlers/generate_setter.rs
@@ -1,10 +1,9 @@
1use stdx::{format_to, to_lower_snake_case}; 1use stdx::{format_to, to_lower_snake_case};
2use syntax::ast::VisibilityOwner; 2use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
3use syntax::ast::{self, AstNode, NameOwner};
4 3
5use crate::{ 4use crate::{
6 utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, 5 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
7 AssistContext, AssistId, AssistKind, Assists, 6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
8}; 7};
9 8
10// Assist: generate_setter 9// Assist: generate_setter
@@ -46,7 +45,8 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext) -> Option<
46 )?; 45 )?;
47 46
48 let target = field.syntax().text_range(); 47 let target = field.syntax().text_range();
49 acc.add( 48 acc.add_group(
49 &GroupLabel("Generate getter/setter".to_owned()),
50 AssistId("generate_setter", AssistKind::Generate), 50 AssistId("generate_setter", AssistKind::Generate),
51 "Generate a setter method", 51 "Generate a setter method",
52 target, 52 target,
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
index 6aa9d2f2c..c69bc5cac 100644
--- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -2,8 +2,7 @@ use ide_db::helpers::mod_path_to_ast;
2use ide_db::imports_locator; 2use ide_db::imports_locator;
3use itertools::Itertools; 3use itertools::Itertools;
4use syntax::{ 4use syntax::{
5 ast::{self, make, AstNode}, 5 ast::{self, make, AstNode, NameOwner},
6 Direction,
7 SyntaxKind::{IDENT, WHITESPACE}, 6 SyntaxKind::{IDENT, WHITESPACE},
8 TextSize, 7 TextSize,
9}; 8};
@@ -11,7 +10,8 @@ use syntax::{
11use crate::{ 10use crate::{
12 assist_context::{AssistBuilder, AssistContext, Assists}, 11 assist_context::{AssistBuilder, AssistContext, Assists},
13 utils::{ 12 utils::{
14 add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, 13 add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text,
14 render_snippet, Cursor, DefaultMethods,
15 }, 15 },
16 AssistId, AssistKind, 16 AssistId, AssistKind,
17}; 17};
@@ -57,8 +57,9 @@ pub(crate) fn replace_derive_with_manual_impl(
57 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; 57 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?;
58 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); 58 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text())));
59 59
60 let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; 60 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
61 let insert_pos = annotated_name.syntax().parent()?.text_range().end(); 61 let annotated_name = adt.name()?;
62 let insert_pos = adt.syntax().text_range().end();
62 63
63 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; 64 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
64 let current_crate = current_module.krate(); 65 let current_crate = current_module.krate();
@@ -82,10 +83,10 @@ pub(crate) fn replace_derive_with_manual_impl(
82 83
83 let mut no_traits_found = true; 84 let mut no_traits_found = true;
84 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { 85 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
85 add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &annotated_name, insert_pos)?; 86 add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?;
86 } 87 }
87 if no_traits_found { 88 if no_traits_found {
88 add_assist(acc, ctx, &attr, &trait_path, None, &annotated_name, insert_pos)?; 89 add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?;
89 } 90 }
90 Some(()) 91 Some(())
91} 92}
@@ -96,6 +97,7 @@ fn add_assist(
96 attr: &ast::Attr, 97 attr: &ast::Attr,
97 trait_path: &ast::Path, 98 trait_path: &ast::Path,
98 trait_: Option<hir::Trait>, 99 trait_: Option<hir::Trait>,
100 adt: &ast::Adt,
99 annotated_name: &ast::Name, 101 annotated_name: &ast::Name,
100 insert_pos: TextSize, 102 insert_pos: TextSize,
101) -> Option<()> { 103) -> Option<()> {
@@ -112,15 +114,15 @@ fn add_assist(
112 let impl_def_with_items = 114 let impl_def_with_items =
113 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); 115 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path);
114 update_attribute(builder, &input, &trait_name, &attr); 116 update_attribute(builder, &input, &trait_name, &attr);
117 let trait_path = format!("{}", trait_path);
115 match (ctx.config.snippet_cap, impl_def_with_items) { 118 match (ctx.config.snippet_cap, impl_def_with_items) {
116 (None, _) => builder.insert( 119 (None, _) => {
117 insert_pos, 120 builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
118 format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name), 121 }
119 ),
120 (Some(cap), None) => builder.insert_snippet( 122 (Some(cap), None) => builder.insert_snippet(
121 cap, 123 cap,
122 insert_pos, 124 insert_pos,
123 format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name), 125 generate_trait_impl_text(adt, &trait_path, " $0"),
124 ), 126 ),
125 (Some(cap), Some((impl_def, first_assoc_item))) => { 127 (Some(cap), Some((impl_def, first_assoc_item))) => {
126 let mut cursor = Cursor::Before(first_assoc_item.syntax()); 128 let mut cursor = Cursor::Before(first_assoc_item.syntax());
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 6f2b22bc2..0516deaff 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -499,7 +499,7 @@ enum A { One(u32) }
499 499
500impl From<u32> for A { 500impl From<u32> for A {
501 fn from(v: u32) -> Self { 501 fn from(v: u32) -> Self {
502 A::One(v) 502 Self::One(v)
503 } 503 }
504} 504}
505"#####, 505"#####,
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 5dd32aef1..8418e6e12 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -2,6 +2,7 @@
2 2
3use std::ops; 3use std::ops;
4 4
5use ast::TypeBoundsOwner;
5use hir::{Adt, HasSource}; 6use hir::{Adt, HasSource};
6use ide_db::{helpers::SnippetCap, RootDatabase}; 7use ide_db::{helpers::SnippetCap, RootDatabase};
7use itertools::Itertools; 8use itertools::Itertools;
@@ -367,21 +368,56 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
367// Generates the surrounding `impl Type { <code> }` including type and lifetime 368// Generates the surrounding `impl Type { <code> }` including type and lifetime
368// parameters 369// parameters
369pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { 370pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
370 let type_params = adt.generic_param_list(); 371 generate_impl_text_inner(adt, None, code)
372}
373
374// Generates the surrounding `impl <trait> for Type { <code> }` including type
375// and lifetime parameters
376pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
377 generate_impl_text_inner(adt, Some(trait_text), code)
378}
379
380fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
381 let generic_params = adt.generic_param_list();
371 let mut buf = String::with_capacity(code.len()); 382 let mut buf = String::with_capacity(code.len());
372 buf.push_str("\n\nimpl"); 383 buf.push_str("\n\n");
373 if let Some(type_params) = &type_params { 384 adt.attrs()
374 format_to!(buf, "{}", type_params.syntax()); 385 .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
386 .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
387 buf.push_str("impl");
388 if let Some(generic_params) = &generic_params {
389 let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
390 let type_params = generic_params.type_params().map(|type_param| {
391 let mut buf = String::new();
392 if let Some(it) = type_param.name() {
393 format_to!(buf, "{}", it.syntax());
394 }
395 if let Some(it) = type_param.colon_token() {
396 format_to!(buf, "{} ", it);
397 }
398 if let Some(it) = type_param.type_bound_list() {
399 format_to!(buf, "{}", it.syntax());
400 }
401 buf
402 });
403 let generics = lifetimes.chain(type_params).format(", ");
404 format_to!(buf, "<{}>", generics);
375 } 405 }
376 buf.push(' '); 406 buf.push(' ');
407 if let Some(trait_text) = trait_text {
408 buf.push_str(trait_text);
409 buf.push_str(" for ");
410 }
377 buf.push_str(adt.name().unwrap().text()); 411 buf.push_str(adt.name().unwrap().text());
378 if let Some(type_params) = type_params { 412 if let Some(generic_params) = generic_params {
379 let lifetime_params = type_params 413 let lifetime_params = generic_params
380 .lifetime_params() 414 .lifetime_params()
381 .filter_map(|it| it.lifetime()) 415 .filter_map(|it| it.lifetime())
382 .map(|it| SmolStr::from(it.text())); 416 .map(|it| SmolStr::from(it.text()));
383 let type_params = 417 let type_params = generic_params
384 type_params.type_params().filter_map(|it| it.name()).map(|it| SmolStr::from(it.text())); 418 .type_params()
419 .filter_map(|it| it.name())
420 .map(|it| SmolStr::from(it.text()));
385 format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) 421 format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", "))
386 } 422 }
387 423