diff options
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter.rs | 173 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter_mut.rs | 195 |
2 files changed, 160 insertions, 208 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 | // ``` |
31 | pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(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 | // ``` | ||
57 | pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
58 | generate_getter_impl(acc, ctx, true) | ||
59 | } | ||
60 | |||
61 | pub(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)] | ||
235 | mod 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#" | ||
249 | struct Context<T: Clone> { | ||
250 | dat$0a: T, | ||
251 | }"#, | ||
252 | r#" | ||
253 | struct Context<T: Clone> { | ||
254 | data: T, | ||
255 | } | ||
256 | |||
257 | impl<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#" | ||
270 | struct Context<T: Clone> { | ||
271 | dat$0a: T, | ||
272 | } | ||
273 | |||
274 | impl<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#" | ||
287 | pub(crate) struct Context<T: Clone> { | ||
288 | dat$0a: T, | ||
289 | }"#, | ||
290 | r#" | ||
291 | pub(crate) struct Context<T: Clone> { | ||
292 | data: T, | ||
293 | } | ||
294 | |||
295 | impl<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#" | ||
309 | struct Context<T: Clone> { | ||
310 | data: T, | ||
311 | cou$0nt: usize, | ||
312 | } | ||
313 | |||
314 | impl<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#" | ||
321 | struct Context<T: Clone> { | ||
322 | data: T, | ||
323 | count: usize, | ||
324 | } | ||
325 | |||
326 | impl<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 | } | ||
diff --git a/crates/ide_assists/src/handlers/generate_getter_mut.rs b/crates/ide_assists/src/handlers/generate_getter_mut.rs deleted file mode 100644 index 821c2eed5..000000000 --- a/crates/ide_assists/src/handlers/generate_getter_mut.rs +++ /dev/null | |||
@@ -1,195 +0,0 @@ | |||
1 | use stdx::{format_to, to_lower_snake_case}; | ||
2 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
3 | |||
4 | use crate::{ | ||
5 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, | ||
6 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
7 | }; | ||
8 | |||
9 | // Assist: generate_getter_mut | ||
10 | // | ||
11 | // Generate a mut getter method. | ||
12 | // | ||
13 | // ``` | ||
14 | // struct Person { | ||
15 | // nam$0e: String, | ||
16 | // } | ||
17 | // ``` | ||
18 | // -> | ||
19 | // ``` | ||
20 | // struct Person { | ||
21 | // name: String, | ||
22 | // } | ||
23 | // | ||
24 | // impl Person { | ||
25 | // /// Get a mutable reference to the person's name. | ||
26 | // fn name_mut(&mut self) -> &mut String { | ||
27 | // &mut self.name | ||
28 | // } | ||
29 | // } | ||
30 | // ``` | ||
31 | pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
32 | let strukt = ctx.find_node_at_offset::<ast::Struct>()?; | ||
33 | let field = ctx.find_node_at_offset::<ast::RecordField>()?; | ||
34 | |||
35 | let strukt_name = strukt.name()?; | ||
36 | let field_name = field.name()?; | ||
37 | let field_ty = field.ty()?; | ||
38 | |||
39 | // Return early if we've found an existing fn | ||
40 | let fn_name = to_lower_snake_case(&field_name.to_string()); | ||
41 | let impl_def = find_struct_impl( | ||
42 | &ctx, | ||
43 | &ast::Adt::Struct(strukt.clone()), | ||
44 | format!("{}_mut", fn_name).as_str(), | ||
45 | )?; | ||
46 | |||
47 | let target = field.syntax().text_range(); | ||
48 | acc.add_group( | ||
49 | &GroupLabel("Generate getter/setter".to_owned()), | ||
50 | AssistId("generate_getter_mut", AssistKind::Generate), | ||
51 | "Generate a mut getter method", | ||
52 | target, | ||
53 | |builder| { | ||
54 | let mut buf = String::with_capacity(512); | ||
55 | let fn_name_spaced = fn_name.replace('_', " "); | ||
56 | let strukt_name_spaced = | ||
57 | to_lower_snake_case(&strukt_name.to_string()).replace('_', " "); | ||
58 | |||
59 | if impl_def.is_some() { | ||
60 | buf.push('\n'); | ||
61 | } | ||
62 | |||
63 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); | ||
64 | format_to!( | ||
65 | buf, | ||
66 | " /// Get a mutable reference to the {}'s {}. | ||
67 | {}fn {}_mut(&mut self) -> &mut {} {{ | ||
68 | &mut self.{} | ||
69 | }}", | ||
70 | strukt_name_spaced, | ||
71 | fn_name_spaced, | ||
72 | vis, | ||
73 | fn_name, | ||
74 | field_ty, | ||
75 | fn_name, | ||
76 | ); | ||
77 | |||
78 | let start_offset = impl_def | ||
79 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) | ||
80 | .unwrap_or_else(|| { | ||
81 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); | ||
82 | strukt.syntax().text_range().end() | ||
83 | }); | ||
84 | |||
85 | builder.insert(start_offset, buf); | ||
86 | }, | ||
87 | ) | ||
88 | } | ||
89 | |||
90 | #[cfg(test)] | ||
91 | mod tests { | ||
92 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
93 | |||
94 | use super::*; | ||
95 | |||
96 | fn check_not_applicable(ra_fixture: &str) { | ||
97 | check_assist_not_applicable(generate_getter_mut, ra_fixture) | ||
98 | } | ||
99 | |||
100 | #[test] | ||
101 | fn test_generate_getter_mut_from_field() { | ||
102 | check_assist( | ||
103 | generate_getter_mut, | ||
104 | r#" | ||
105 | struct Context<T: Clone> { | ||
106 | dat$0a: T, | ||
107 | }"#, | ||
108 | r#" | ||
109 | struct Context<T: Clone> { | ||
110 | data: T, | ||
111 | } | ||
112 | |||
113 | impl<T: Clone> Context<T> { | ||
114 | /// Get a mutable reference to the context's data. | ||
115 | fn data_mut(&mut self) -> &mut T { | ||
116 | &mut self.data | ||
117 | } | ||
118 | }"#, | ||
119 | ); | ||
120 | } | ||
121 | |||
122 | #[test] | ||
123 | fn test_generate_getter_mut_already_implemented() { | ||
124 | check_not_applicable( | ||
125 | r#" | ||
126 | struct Context<T: Clone> { | ||
127 | dat$0a: T, | ||
128 | } | ||
129 | |||
130 | impl<T: Clone> Context<T> { | ||
131 | fn data_mut(&mut self) -> &mut T { | ||
132 | &mut self.data | ||
133 | } | ||
134 | }"#, | ||
135 | ); | ||
136 | } | ||
137 | |||
138 | #[test] | ||
139 | fn test_generate_getter_mut_from_field_with_visibility_marker() { | ||
140 | check_assist( | ||
141 | generate_getter_mut, | ||
142 | r#" | ||
143 | pub(crate) struct Context<T: Clone> { | ||
144 | dat$0a: T, | ||
145 | }"#, | ||
146 | r#" | ||
147 | pub(crate) struct Context<T: Clone> { | ||
148 | data: T, | ||
149 | } | ||
150 | |||
151 | impl<T: Clone> Context<T> { | ||
152 | /// Get a mutable reference to the context's data. | ||
153 | pub(crate) fn data_mut(&mut self) -> &mut T { | ||
154 | &mut self.data | ||
155 | } | ||
156 | }"#, | ||
157 | ); | ||
158 | } | ||
159 | |||
160 | #[test] | ||
161 | fn test_multiple_generate_getter_mut() { | ||
162 | check_assist( | ||
163 | generate_getter_mut, | ||
164 | r#" | ||
165 | struct Context<T: Clone> { | ||
166 | data: T, | ||
167 | cou$0nt: usize, | ||
168 | } | ||
169 | |||
170 | impl<T: Clone> Context<T> { | ||
171 | /// Get a mutable reference to the context's data. | ||
172 | fn data_mut(&mut self) -> &mut T { | ||
173 | &mut self.data | ||
174 | } | ||
175 | }"#, | ||
176 | r#" | ||
177 | struct Context<T: Clone> { | ||
178 | data: T, | ||
179 | count: usize, | ||
180 | } | ||
181 | |||
182 | impl<T: Clone> Context<T> { | ||
183 | /// Get a mutable reference to the context's data. | ||
184 | fn data_mut(&mut self) -> &mut T { | ||
185 | &mut self.data | ||
186 | } | ||
187 | |||
188 | /// Get a mutable reference to the context's count. | ||
189 | fn count_mut(&mut self) -> &mut usize { | ||
190 | &mut self.count | ||
191 | } | ||
192 | }"#, | ||
193 | ); | ||
194 | } | ||
195 | } | ||