aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists')
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_match_method.rs406
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_projection_method.rs307
-rw-r--r--crates/ide_assists/src/lib.rs5
-rw-r--r--crates/ide_assists/src/utils.rs24
4 files changed, 340 insertions, 402 deletions
diff --git a/crates/ide_assists/src/handlers/generate_enum_match_method.rs b/crates/ide_assists/src/handlers/generate_enum_match_method.rs
index 670c82200..7e181a480 100644
--- a/crates/ide_assists/src/handlers/generate_enum_match_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_match_method.rs
@@ -1,11 +1,9 @@
1use itertools::Itertools;
2use stdx::to_lower_snake_case; 1use stdx::to_lower_snake_case;
3use syntax::ast::VisibilityOwner; 2use syntax::ast::VisibilityOwner;
4use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
5 4
6use crate::{ 5use crate::{
7 assist_context::AssistBuilder, 6 utils::{add_method_to_adt, find_struct_impl},
8 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
9 AssistContext, AssistId, AssistKind, Assists, 7 AssistContext, AssistId, AssistKind, Assists,
10}; 8};
11 9
@@ -39,7 +37,11 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
39 let variant = ctx.find_node_at_offset::<ast::Variant>()?; 37 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
40 let variant_name = variant.name()?; 38 let variant_name = variant.name()?;
41 let parent_enum = ast::Adt::Enum(variant.parent_enum()); 39 let parent_enum = ast::Adt::Enum(variant.parent_enum());
42 let variant_kind = variant_kind(&variant); 40 let pattern_suffix = match variant.kind() {
41 ast::StructKind::Record(_) => " { .. }",
42 ast::StructKind::Tuple(_) => "(..)",
43 ast::StructKind::Unit => "",
44 };
43 45
44 let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string()); 46 let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string());
45 let fn_name = format!("is_{}", &to_lower_snake_case(variant_name.text())); 47 let fn_name = format!("is_{}", &to_lower_snake_case(variant_name.text()));
@@ -59,12 +61,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
59 {}fn {}(&self) -> bool {{ 61 {}fn {}(&self) -> bool {{
60 matches!(self, Self::{}{}) 62 matches!(self, Self::{}{})
61 }}", 63 }}",
62 enum_lowercase_name, 64 enum_lowercase_name, variant_name, vis, fn_name, variant_name, pattern_suffix,
63 variant_name,
64 vis,
65 fn_name,
66 variant_name,
67 variant_kind.pattern_suffix(),
68 ); 65 );
69 66
70 add_method_to_adt(builder, &parent_enum, impl_def, &method); 67 add_method_to_adt(builder, &parent_enum, impl_def, &method);
@@ -72,237 +69,6 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
72 ) 69 )
73} 70}
74 71
75// Assist: generate_enum_into_method
76//
77// Generate an `into_` method for an enum variant.
78//
79// ```
80// enum Value {
81// Number(i32),
82// Text(String)$0,
83// }
84// ```
85// ->
86// ```
87// enum Value {
88// Number(i32),
89// Text(String),
90// }
91//
92// impl Value {
93// fn into_text(self) -> Option<String> {
94// if let Self::Text(v) = self {
95// Some(v)
96// } else {
97// None
98// }
99// }
100// }
101// ```
102pub(crate) fn generate_enum_into_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
103 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
104 let variant_name = variant.name()?;
105 let parent_enum = ast::Adt::Enum(variant.parent_enum());
106 let variant_kind = variant_kind(&variant);
107
108 let fn_name = format!("into_{}", &to_lower_snake_case(variant_name.text()));
109
110 // Return early if we've found an existing new fn
111 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?;
112
113 let field_type = variant_kind.single_field_type()?;
114 let (pattern_suffix, bound_name) = variant_kind.binding_pattern()?;
115
116 let target = variant.syntax().text_range();
117 acc.add(
118 AssistId("generate_enum_into_method", AssistKind::Generate),
119 "Generate an `into_` method for an enum variant",
120 target,
121 |builder| {
122 let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
123 let method = format!(
124 " {}fn {}(self) -> Option<{}> {{
125 if let Self::{}{} = self {{
126 Some({})
127 }} else {{
128 None
129 }}
130 }}",
131 vis,
132 fn_name,
133 field_type.syntax(),
134 variant_name,
135 pattern_suffix,
136 bound_name,
137 );
138
139 add_method_to_adt(builder, &parent_enum, impl_def, &method);
140 },
141 )
142}
143
144// Assist: generate_enum_as_method
145//
146// Generate an `as_` method for an enum variant.
147//
148// ```
149// enum Value {
150// Number(i32),
151// Text(String)$0,
152// }
153// ```
154// ->
155// ```
156// enum Value {
157// Number(i32),
158// Text(String),
159// }
160//
161// impl Value {
162// fn as_text(&self) -> Option<&String> {
163// if let Self::Text(v) = self {
164// Some(v)
165// } else {
166// None
167// }
168// }
169// }
170// ```
171pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
172 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
173 let variant_name = variant.name()?;
174 let parent_enum = ast::Adt::Enum(variant.parent_enum());
175 let variant_kind = variant_kind(&variant);
176
177 let fn_name = format!("as_{}", &to_lower_snake_case(variant_name.text()));
178
179 // Return early if we've found an existing new fn
180 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?;
181
182 let field_type = variant_kind.single_field_type()?;
183 let (pattern_suffix, bound_name) = variant_kind.binding_pattern()?;
184
185 let target = variant.syntax().text_range();
186 acc.add(
187 AssistId("generate_enum_as_method", AssistKind::Generate),
188 "Generate an `as_` method for an enum variant",
189 target,
190 |builder| {
191 let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
192 let method = format!(
193 " {}fn {}(&self) -> Option<&{}> {{
194 if let Self::{}{} = self {{
195 Some({})
196 }} else {{
197 None
198 }}
199 }}",
200 vis,
201 fn_name,
202 field_type.syntax(),
203 variant_name,
204 pattern_suffix,
205 bound_name,
206 );
207
208 add_method_to_adt(builder, &parent_enum, impl_def, &method);
209 },
210 )
211}
212
213fn add_method_to_adt(
214 builder: &mut AssistBuilder,
215 adt: &ast::Adt,
216 impl_def: Option<ast::Impl>,
217 method: &str,
218) {
219 let mut buf = String::with_capacity(method.len() + 2);
220 if impl_def.is_some() {
221 buf.push('\n');
222 }
223 buf.push_str(method);
224
225 let start_offset = impl_def
226 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
227 .unwrap_or_else(|| {
228 buf = generate_impl_text(&adt, &buf);
229 adt.syntax().text_range().end()
230 });
231
232 builder.insert(start_offset, buf);
233}
234
235enum VariantKind {
236 Unit,
237 /// Tuple with a single field
238 NewtypeTuple {
239 ty: Option<ast::Type>,
240 },
241 /// Tuple with 0 or more than 2 fields
242 Tuple,
243 /// Record with a single field
244 NewtypeRecord {
245 field_name: Option<ast::Name>,
246 field_type: Option<ast::Type>,
247 },
248 /// Record with 0 or more than 2 fields
249 Record,
250}
251
252impl VariantKind {
253 fn pattern_suffix(&self) -> &'static str {
254 match self {
255 VariantKind::Unit => "",
256 VariantKind::NewtypeTuple { .. } | VariantKind::Tuple => "(..)",
257 VariantKind::NewtypeRecord { .. } | VariantKind::Record => " { .. }",
258 }
259 }
260
261 fn binding_pattern(&self) -> Option<(String, String)> {
262 match self {
263 VariantKind::Unit
264 | VariantKind::Tuple
265 | VariantKind::Record
266 | VariantKind::NewtypeRecord { field_name: None, .. } => None,
267 VariantKind::NewtypeTuple { .. } => Some(("(v)".to_owned(), "v".to_owned())),
268 VariantKind::NewtypeRecord { field_name: Some(name), .. } => {
269 Some((format!(" {{ {} }}", name.syntax()), name.syntax().to_string()))
270 }
271 }
272 }
273
274 fn single_field_type(&self) -> Option<&ast::Type> {
275 match self {
276 VariantKind::Unit | VariantKind::Tuple | VariantKind::Record => None,
277 VariantKind::NewtypeTuple { ty } => ty.as_ref(),
278 VariantKind::NewtypeRecord { field_type, .. } => field_type.as_ref(),
279 }
280 }
281}
282
283fn variant_kind(variant: &ast::Variant) -> VariantKind {
284 match variant.kind() {
285 ast::StructKind::Record(record) => {
286 if let Some((single_field,)) = record.fields().collect_tuple() {
287 let field_name = single_field.name();
288 let field_type = single_field.ty();
289 VariantKind::NewtypeRecord { field_name, field_type }
290 } else {
291 VariantKind::Record
292 }
293 }
294 ast::StructKind::Tuple(tuple) => {
295 if let Some((single_field,)) = tuple.fields().collect_tuple() {
296 let ty = single_field.ty();
297 VariantKind::NewtypeTuple { ty }
298 } else {
299 VariantKind::Tuple
300 }
301 }
302 ast::StructKind::Unit => VariantKind::Unit,
303 }
304}
305
306#[cfg(test)] 72#[cfg(test)]
307mod tests { 73mod tests {
308 use crate::tests::{check_assist, check_assist_not_applicable}; 74 use crate::tests::{check_assist, check_assist_not_applicable};
@@ -481,162 +247,4 @@ impl Variant {
481}"#, 247}"#,
482 ); 248 );
483 } 249 }
484
485 #[test]
486 fn test_generate_enum_into_tuple_variant() {
487 check_assist(
488 generate_enum_into_method,
489 r#"
490enum Value {
491 Number(i32),
492 Text(String)$0,
493}"#,
494 r#"enum Value {
495 Number(i32),
496 Text(String),
497}
498
499impl Value {
500 fn into_text(self) -> Option<String> {
501 if let Self::Text(v) = self {
502 Some(v)
503 } else {
504 None
505 }
506 }
507}"#,
508 );
509 }
510
511 #[test]
512 fn test_generate_enum_into_already_implemented() {
513 check_assist_not_applicable(
514 generate_enum_into_method,
515 r#"enum Value {
516 Number(i32),
517 Text(String)$0,
518}
519
520impl Value {
521 fn into_text(self) -> Option<String> {
522 if let Self::Text(v) = self {
523 Some(v)
524 } else {
525 None
526 }
527 }
528}"#,
529 );
530 }
531
532 #[test]
533 fn test_generate_enum_into_unit_variant() {
534 check_assist_not_applicable(
535 generate_enum_into_method,
536 r#"enum Value {
537 Number(i32),
538 Text(String),
539 Unit$0,
540}"#,
541 );
542 }
543
544 #[test]
545 fn test_generate_enum_into_record_with_multiple_fields() {
546 check_assist_not_applicable(
547 generate_enum_into_method,
548 r#"enum Value {
549 Number(i32),
550 Text(String),
551 Both { first: i32, second: String }$0,
552}"#,
553 );
554 }
555
556 #[test]
557 fn test_generate_enum_into_tuple_with_multiple_fields() {
558 check_assist_not_applicable(
559 generate_enum_into_method,
560 r#"enum Value {
561 Number(i32),
562 Text(String, String)$0,
563}"#,
564 );
565 }
566
567 #[test]
568 fn test_generate_enum_into_record_variant() {
569 check_assist(
570 generate_enum_into_method,
571 r#"enum Value {
572 Number(i32),
573 Text { text: String }$0,
574}"#,
575 r#"enum Value {
576 Number(i32),
577 Text { text: String },
578}
579
580impl Value {
581 fn into_text(self) -> Option<String> {
582 if let Self::Text { text } = self {
583 Some(text)
584 } else {
585 None
586 }
587 }
588}"#,
589 );
590 }
591
592 #[test]
593 fn test_generate_enum_as_tuple_variant() {
594 check_assist(
595 generate_enum_as_method,
596 r#"
597enum Value {
598 Number(i32),
599 Text(String)$0,
600}"#,
601 r#"enum Value {
602 Number(i32),
603 Text(String),
604}
605
606impl Value {
607 fn as_text(&self) -> Option<&String> {
608 if let Self::Text(v) = self {
609 Some(v)
610 } else {
611 None
612 }
613 }
614}"#,
615 );
616 }
617
618 #[test]
619 fn test_generate_enum_as_record_variant() {
620 check_assist(
621 generate_enum_as_method,
622 r#"enum Value {
623 Number(i32),
624 Text { text: String }$0,
625}"#,
626 r#"enum Value {
627 Number(i32),
628 Text { text: String },
629}
630
631impl Value {
632 fn as_text(&self) -> Option<&String> {
633 if let Self::Text { text } = self {
634 Some(text)
635 } else {
636 None
637 }
638 }
639}"#,
640 );
641 }
642} 250}
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
new file mode 100644
index 000000000..71447f310
--- /dev/null
+++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
@@ -0,0 +1,307 @@
1use itertools::Itertools;
2use stdx::to_lower_snake_case;
3use syntax::ast::VisibilityOwner;
4use syntax::ast::{self, AstNode, NameOwner};
5
6use crate::{
7 utils::{add_method_to_adt, find_struct_impl},
8 AssistContext, AssistId, AssistKind, Assists,
9};
10
11// Assist: generate_enum_into_method
12//
13// Generate an `into_` method for an enum variant.
14//
15// ```
16// enum Value {
17// Number(i32),
18// Text(String)$0,
19// }
20// ```
21// ->
22// ```
23// enum Value {
24// Number(i32),
25// Text(String),
26// }
27//
28// impl Value {
29// fn into_text(self) -> Option<String> {
30// if let Self::Text(v) = self {
31// Some(v)
32// } else {
33// None
34// }
35// }
36// }
37// ```
38pub(crate) fn generate_enum_into_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 generate_enum_projection_method(
40 acc,
41 ctx,
42 "generate_enum_into_method",
43 "Generate an `into_` method for an enum variant",
44 "into",
45 "",
46 )
47}
48
49// Assist: generate_enum_as_method
50//
51// Generate an `as_` method for an enum variant.
52//
53// ```
54// enum Value {
55// Number(i32),
56// Text(String)$0,
57// }
58// ```
59// ->
60// ```
61// enum Value {
62// Number(i32),
63// Text(String),
64// }
65//
66// impl Value {
67// fn as_text(&self) -> Option<&String> {
68// if let Self::Text(v) = self {
69// Some(v)
70// } else {
71// None
72// }
73// }
74// }
75// ```
76pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
77 generate_enum_projection_method(
78 acc,
79 ctx,
80 "generate_enum_as_method",
81 "Generate an `as_` method for an enum variant",
82 "as",
83 "&",
84 )
85}
86
87pub(crate) fn generate_enum_projection_method(
88 acc: &mut Assists,
89 ctx: &AssistContext,
90 assist_id: &'static str,
91 assist_description: &str,
92 fn_name_prefix: &str,
93 ref_prefix: &str,
94) -> Option<()> {
95 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
96 let variant_name = variant.name()?;
97 let parent_enum = ast::Adt::Enum(variant.parent_enum());
98
99 let (pattern_suffix, field_type, bound_name) = match variant.kind() {
100 ast::StructKind::Record(record) => {
101 let (field,) = record.fields().collect_tuple()?;
102 let name = field.name()?.to_string();
103 let ty = field.ty()?;
104 let pattern_suffix = format!(" {{ {} }}", name);
105 (pattern_suffix, ty, name)
106 }
107 ast::StructKind::Tuple(tuple) => {
108 let (field,) = tuple.fields().collect_tuple()?;
109 let ty = field.ty()?;
110 ("(v)".to_owned(), ty, "v".to_owned())
111 }
112 ast::StructKind::Unit => return None,
113 };
114
115 let fn_name = format!("{}_{}", fn_name_prefix, &to_lower_snake_case(variant_name.text()));
116
117 // Return early if we've found an existing new fn
118 let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?;
119
120 let target = variant.syntax().text_range();
121 acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| {
122 let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
123 let method = format!(
124 " {0}fn {1}({2}self) -> Option<{2}{3}> {{
125 if let Self::{4}{5} = self {{
126 Some({6})
127 }} else {{
128 None
129 }}
130 }}",
131 vis,
132 fn_name,
133 ref_prefix,
134 field_type.syntax(),
135 variant_name,
136 pattern_suffix,
137 bound_name,
138 );
139
140 add_method_to_adt(builder, &parent_enum, impl_def, &method);
141 })
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::tests::{check_assist, check_assist_not_applicable};
147
148 use super::*;
149
150 #[test]
151 fn test_generate_enum_into_tuple_variant() {
152 check_assist(
153 generate_enum_into_method,
154 r#"
155enum Value {
156 Number(i32),
157 Text(String)$0,
158}"#,
159 r#"enum Value {
160 Number(i32),
161 Text(String),
162}
163
164impl Value {
165 fn into_text(self) -> Option<String> {
166 if let Self::Text(v) = self {
167 Some(v)
168 } else {
169 None
170 }
171 }
172}"#,
173 );
174 }
175
176 #[test]
177 fn test_generate_enum_into_already_implemented() {
178 check_assist_not_applicable(
179 generate_enum_into_method,
180 r#"enum Value {
181 Number(i32),
182 Text(String)$0,
183}
184
185impl Value {
186 fn into_text(self) -> Option<String> {
187 if let Self::Text(v) = self {
188 Some(v)
189 } else {
190 None
191 }
192 }
193}"#,
194 );
195 }
196
197 #[test]
198 fn test_generate_enum_into_unit_variant() {
199 check_assist_not_applicable(
200 generate_enum_into_method,
201 r#"enum Value {
202 Number(i32),
203 Text(String),
204 Unit$0,
205}"#,
206 );
207 }
208
209 #[test]
210 fn test_generate_enum_into_record_with_multiple_fields() {
211 check_assist_not_applicable(
212 generate_enum_into_method,
213 r#"enum Value {
214 Number(i32),
215 Text(String),
216 Both { first: i32, second: String }$0,
217}"#,
218 );
219 }
220
221 #[test]
222 fn test_generate_enum_into_tuple_with_multiple_fields() {
223 check_assist_not_applicable(
224 generate_enum_into_method,
225 r#"enum Value {
226 Number(i32),
227 Text(String, String)$0,
228}"#,
229 );
230 }
231
232 #[test]
233 fn test_generate_enum_into_record_variant() {
234 check_assist(
235 generate_enum_into_method,
236 r#"enum Value {
237 Number(i32),
238 Text { text: String }$0,
239}"#,
240 r#"enum Value {
241 Number(i32),
242 Text { text: String },
243}
244
245impl Value {
246 fn into_text(self) -> Option<String> {
247 if let Self::Text { text } = self {
248 Some(text)
249 } else {
250 None
251 }
252 }
253}"#,
254 );
255 }
256
257 #[test]
258 fn test_generate_enum_as_tuple_variant() {
259 check_assist(
260 generate_enum_as_method,
261 r#"
262enum Value {
263 Number(i32),
264 Text(String)$0,
265}"#,
266 r#"enum Value {
267 Number(i32),
268 Text(String),
269}
270
271impl Value {
272 fn as_text(&self) -> Option<&String> {
273 if let Self::Text(v) = self {
274 Some(v)
275 } else {
276 None
277 }
278 }
279}"#,
280 );
281 }
282
283 #[test]
284 fn test_generate_enum_as_record_variant() {
285 check_assist(
286 generate_enum_as_method,
287 r#"enum Value {
288 Number(i32),
289 Text { text: String }$0,
290}"#,
291 r#"enum Value {
292 Number(i32),
293 Text { text: String },
294}
295
296impl Value {
297 fn as_text(&self) -> Option<&String> {
298 if let Self::Text { text } = self {
299 Some(text)
300 } else {
301 None
302 }
303 }
304}"#,
305 );
306 }
307}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 84ac928e9..4a7cd5848 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -129,6 +129,7 @@ mod handlers {
129 mod generate_default_from_enum_variant; 129 mod generate_default_from_enum_variant;
130 mod generate_derive; 130 mod generate_derive;
131 mod generate_enum_match_method; 131 mod generate_enum_match_method;
132 mod generate_enum_projection_method;
132 mod generate_from_impl_for_enum; 133 mod generate_from_impl_for_enum;
133 mod generate_function; 134 mod generate_function;
134 mod generate_getter; 135 mod generate_getter;
@@ -190,8 +191,8 @@ mod handlers {
190 generate_default_from_enum_variant::generate_default_from_enum_variant, 191 generate_default_from_enum_variant::generate_default_from_enum_variant,
191 generate_derive::generate_derive, 192 generate_derive::generate_derive,
192 generate_enum_match_method::generate_enum_is_method, 193 generate_enum_match_method::generate_enum_is_method,
193 generate_enum_match_method::generate_enum_into_method, 194 generate_enum_projection_method::generate_enum_into_method,
194 generate_enum_match_method::generate_enum_as_method, 195 generate_enum_projection_method::generate_enum_as_method,
195 generate_from_impl_for_enum::generate_from_impl_for_enum, 196 generate_from_impl_for_enum::generate_from_impl_for_enum,
196 generate_function::generate_function, 197 generate_function::generate_function,
197 generate_getter::generate_getter, 198 generate_getter::generate_getter,
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 276792bc1..880ab6fe3 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -21,7 +21,7 @@ use syntax::{
21}; 21};
22 22
23use crate::{ 23use crate::{
24 assist_context::AssistContext, 24 assist_context::{AssistBuilder, AssistContext},
25 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 25 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
26}; 26};
27 27
@@ -464,3 +464,25 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
464 464
465 buf 465 buf
466} 466}
467
468pub(crate) fn add_method_to_adt(
469 builder: &mut AssistBuilder,
470 adt: &ast::Adt,
471 impl_def: Option<ast::Impl>,
472 method: &str,
473) {
474 let mut buf = String::with_capacity(method.len() + 2);
475 if impl_def.is_some() {
476 buf.push('\n');
477 }
478 buf.push_str(method);
479
480 let start_offset = impl_def
481 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
482 .unwrap_or_else(|| {
483 buf = generate_impl_text(&adt, &buf);
484 adt.syntax().text_range().end()
485 });
486
487 builder.insert(start_offset, buf);
488}