aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/generate_getter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/generate_getter.rs')
-rw-r--r--crates/ide_assists/src/handlers/generate_getter.rs173
1 files changed, 160 insertions, 13 deletions
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index df7d1bb95..e01985112 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -29,6 +29,40 @@ use crate::{
29// } 29// }
30// ``` 30// ```
31pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 generate_getter_impl(acc, ctx, false)
33}
34
35// Assist: generate_getter_mut
36//
37// Generate a mut getter method.
38//
39// ```
40// struct Person {
41// nam$0e: String,
42// }
43// ```
44// ->
45// ```
46// struct Person {
47// name: String,
48// }
49//
50// impl Person {
51// /// Get a mutable reference to the person's name.
52// fn name_mut(&mut self) -> &mut String {
53// &mut self.name
54// }
55// }
56// ```
57pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
58 generate_getter_impl(acc, ctx, true)
59}
60
61pub(crate) fn generate_getter_impl(
62 acc: &mut Assists,
63 ctx: &AssistContext,
64 mutable: bool,
65) -> Option<()> {
32 let strukt = ctx.find_node_at_offset::<ast::Struct>()?; 66 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
33 let field = ctx.find_node_at_offset::<ast::RecordField>()?; 67 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
34 68
@@ -37,22 +71,26 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
37 let field_ty = field.ty()?; 71 let field_ty = field.ty()?;
38 72
39 // Return early if we've found an existing fn 73 // Return early if we've found an existing fn
40 let fn_name = to_lower_snake_case(&field_name.to_string()); 74 let mut fn_name = to_lower_snake_case(&field_name.to_string());
75 if mutable {
76 format_to!(fn_name, "_mut");
77 }
41 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; 78 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?;
42 79
80 let (id, label) = if mutable {
81 ("generate_getter_mut", "Generate a mut getter method")
82 } else {
83 ("generate_getter", "Generate a getter method")
84 };
43 let target = field.syntax().text_range(); 85 let target = field.syntax().text_range();
44 acc.add_group( 86 acc.add_group(
45 &GroupLabel("Generate getter/setter".to_owned()), 87 &GroupLabel("Generate getter/setter".to_owned()),
46 AssistId("generate_getter", AssistKind::Generate), 88 AssistId(id, AssistKind::Generate),
47 "Generate a getter method", 89 label,
48 target, 90 target,
49 |builder| { 91 |builder| {
50 let mut buf = String::with_capacity(512); 92 let mut buf = String::with_capacity(512);
51 93
52 let fn_name_spaced = fn_name.replace('_', " ");
53 let strukt_name_spaced =
54 to_lower_snake_case(&strukt_name.to_string()).replace('_', " ");
55
56 if impl_def.is_some() { 94 if impl_def.is_some() {
57 buf.push('\n'); 95 buf.push('\n');
58 } 96 }
@@ -60,16 +98,18 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
60 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); 98 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
61 format_to!( 99 format_to!(
62 buf, 100 buf,
63 " /// Get a reference to the {}'s {}. 101 " /// Get a {}reference to the {}'s {}.
64 {}fn {}(&self) -> &{} {{ 102 {}fn {}(&{mut_}self) -> &{mut_}{} {{
65 &self.{} 103 &{mut_}self.{}
66 }}", 104 }}",
67 strukt_name_spaced, 105 mutable.then(|| "mutable ").unwrap_or_default(),
68 fn_name_spaced, 106 to_lower_snake_case(&strukt_name.to_string()).replace('_', " "),
107 fn_name.trim_end_matches("_mut").replace('_', " "),
69 vis, 108 vis,
70 fn_name, 109 fn_name,
71 field_ty, 110 field_ty,
72 fn_name, 111 field_name,
112 mut_ = mutable.then(|| "mut ").unwrap_or_default(),
73 ); 113 );
74 114
75 let start_offset = impl_def 115 let start_offset = impl_def
@@ -190,3 +230,110 @@ impl<T: Clone> Context<T> {
190 ); 230 );
191 } 231 }
192} 232}
233
234#[cfg(test)]
235mod tests_mut {
236 use crate::tests::{check_assist, check_assist_not_applicable};
237
238 use super::*;
239
240 fn check_not_applicable(ra_fixture: &str) {
241 check_assist_not_applicable(generate_getter_mut, ra_fixture)
242 }
243
244 #[test]
245 fn test_generate_getter_mut_from_field() {
246 check_assist(
247 generate_getter_mut,
248 r#"
249struct Context<T: Clone> {
250 dat$0a: T,
251}"#,
252 r#"
253struct Context<T: Clone> {
254 data: T,
255}
256
257impl<T: Clone> Context<T> {
258 /// Get a mutable reference to the context's data.
259 fn data_mut(&mut self) -> &mut T {
260 &mut self.data
261 }
262}"#,
263 );
264 }
265
266 #[test]
267 fn test_generate_getter_mut_already_implemented() {
268 check_not_applicable(
269 r#"
270struct Context<T: Clone> {
271 dat$0a: T,
272}
273
274impl<T: Clone> Context<T> {
275 fn data_mut(&mut self) -> &mut T {
276 &mut self.data
277 }
278}"#,
279 );
280 }
281
282 #[test]
283 fn test_generate_getter_mut_from_field_with_visibility_marker() {
284 check_assist(
285 generate_getter_mut,
286 r#"
287pub(crate) struct Context<T: Clone> {
288 dat$0a: T,
289}"#,
290 r#"
291pub(crate) struct Context<T: Clone> {
292 data: T,
293}
294
295impl<T: Clone> Context<T> {
296 /// Get a mutable reference to the context's data.
297 pub(crate) fn data_mut(&mut self) -> &mut T {
298 &mut self.data
299 }
300}"#,
301 );
302 }
303
304 #[test]
305 fn test_multiple_generate_getter_mut() {
306 check_assist(
307 generate_getter_mut,
308 r#"
309struct Context<T: Clone> {
310 data: T,
311 cou$0nt: usize,
312}
313
314impl<T: Clone> Context<T> {
315 /// Get a mutable reference to the context's data.
316 fn data_mut(&mut self) -> &mut T {
317 &mut self.data
318 }
319}"#,
320 r#"
321struct Context<T: Clone> {
322 data: T,
323 count: usize,
324}
325
326impl<T: Clone> Context<T> {
327 /// Get a mutable reference to the context's data.
328 fn data_mut(&mut self) -> &mut T {
329 &mut self.data
330 }
331
332 /// Get a mutable reference to the context's count.
333 fn count_mut(&mut self) -> &mut usize {
334 &mut self.count
335 }
336}"#,
337 );
338 }
339}