diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-23 21:48:35 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-23 21:48:35 +0100 |
commit | 951c0e95f44bf7947c2a46ef9e8ff2616823faba (patch) | |
tree | f202726bcd9676b919d04d638f9fafa6f9b801e9 /crates/ide_assists/src/handlers | |
parent | e0864c9c153c88a4bc3b75d0cc5501678a21183a (diff) | |
parent | 8696c82777f9992fceadc531536bf90b64cf753d (diff) |
Merge #8948
8948: feat: generate getter assist places the cursor at the generated function r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter.rs | 189 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter_mut.rs | 195 |
2 files changed, 137 insertions, 247 deletions
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs index df7d1bb95..9faaaf284 100644 --- a/crates/ide_assists/src/handlers/generate_getter.rs +++ b/crates/ide_assists/src/handlers/generate_getter.rs | |||
@@ -23,12 +23,46 @@ use crate::{ | |||
23 | // | 23 | // |
24 | // impl Person { | 24 | // impl Person { |
25 | // /// Get a reference to the person's name. | 25 | // /// Get a reference to the person's name. |
26 | // fn name(&self) -> &String { | 26 | // fn $0name(&self) -> &String { |
27 | // &self.name | 27 | // &self.name |
28 | // } | 28 | // } |
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 $0name_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 |
@@ -79,7 +119,12 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
79 | strukt.syntax().text_range().end() | 119 | strukt.syntax().text_range().end() |
80 | }); | 120 | }); |
81 | 121 | ||
82 | builder.insert(start_offset, buf); | 122 | match ctx.config.snippet_cap { |
123 | Some(cap) => { | ||
124 | builder.insert_snippet(cap, start_offset, buf.replacen("fn ", "fn $0", 1)) | ||
125 | } | ||
126 | None => builder.insert(start_offset, buf), | ||
127 | } | ||
83 | }, | 128 | }, |
84 | ) | 129 | ) |
85 | } | 130 | } |
@@ -90,45 +135,81 @@ mod tests { | |||
90 | 135 | ||
91 | use super::*; | 136 | use super::*; |
92 | 137 | ||
93 | fn check_not_applicable(ra_fixture: &str) { | ||
94 | check_assist_not_applicable(generate_getter, ra_fixture) | ||
95 | } | ||
96 | |||
97 | #[test] | 138 | #[test] |
98 | fn test_generate_getter_from_field() { | 139 | fn test_generate_getter_from_field() { |
99 | check_assist( | 140 | check_assist( |
100 | generate_getter, | 141 | generate_getter, |
101 | r#" | 142 | r#" |
102 | struct Context<T: Clone> { | 143 | struct Context { |
103 | dat$0a: T, | 144 | dat$0a: Data, |
104 | }"#, | 145 | } |
146 | "#, | ||
105 | r#" | 147 | r#" |
106 | struct Context<T: Clone> { | 148 | struct Context { |
107 | data: T, | 149 | data: Data, |
108 | } | 150 | } |
109 | 151 | ||
110 | impl<T: Clone> Context<T> { | 152 | impl Context { |
111 | /// Get a reference to the context's data. | 153 | /// Get a reference to the context's data. |
112 | fn data(&self) -> &T { | 154 | fn $0data(&self) -> &Data { |
113 | &self.data | 155 | &self.data |
114 | } | 156 | } |
115 | }"#, | 157 | } |
158 | "#, | ||
159 | ); | ||
160 | |||
161 | check_assist( | ||
162 | generate_getter_mut, | ||
163 | r#" | ||
164 | struct Context { | ||
165 | dat$0a: Data, | ||
166 | } | ||
167 | "#, | ||
168 | r#" | ||
169 | struct Context { | ||
170 | data: Data, | ||
171 | } | ||
172 | |||
173 | impl Context { | ||
174 | /// Get a mutable reference to the context's data. | ||
175 | fn $0data_mut(&mut self) -> &mut Data { | ||
176 | &mut self.data | ||
177 | } | ||
178 | } | ||
179 | "#, | ||
116 | ); | 180 | ); |
117 | } | 181 | } |
118 | 182 | ||
119 | #[test] | 183 | #[test] |
120 | fn test_generate_getter_already_implemented() { | 184 | fn test_generate_getter_already_implemented() { |
121 | check_not_applicable( | 185 | check_assist_not_applicable( |
186 | generate_getter, | ||
122 | r#" | 187 | r#" |
123 | struct Context<T: Clone> { | 188 | struct Context { |
124 | dat$0a: T, | 189 | dat$0a: Data, |
125 | } | 190 | } |
126 | 191 | ||
127 | impl<T: Clone> Context<T> { | 192 | impl Context { |
128 | fn data(&self) -> &T { | 193 | fn data(&self) -> &Data { |
129 | &self.data | 194 | &self.data |
130 | } | 195 | } |
131 | }"#, | 196 | } |
197 | "#, | ||
198 | ); | ||
199 | |||
200 | check_assist_not_applicable( | ||
201 | generate_getter_mut, | ||
202 | r#" | ||
203 | struct Context { | ||
204 | dat$0a: Data, | ||
205 | } | ||
206 | |||
207 | impl Context { | ||
208 | fn data_mut(&mut self) -> &mut Data { | ||
209 | &mut self.data | ||
210 | } | ||
211 | } | ||
212 | "#, | ||
132 | ); | 213 | ); |
133 | } | 214 | } |
134 | 215 | ||
@@ -137,20 +218,22 @@ impl<T: Clone> Context<T> { | |||
137 | check_assist( | 218 | check_assist( |
138 | generate_getter, | 219 | generate_getter, |
139 | r#" | 220 | r#" |
140 | pub(crate) struct Context<T: Clone> { | 221 | pub(crate) struct Context { |
141 | dat$0a: T, | 222 | dat$0a: Data, |
142 | }"#, | 223 | } |
224 | "#, | ||
143 | r#" | 225 | r#" |
144 | pub(crate) struct Context<T: Clone> { | 226 | pub(crate) struct Context { |
145 | data: T, | 227 | data: Data, |
146 | } | 228 | } |
147 | 229 | ||
148 | impl<T: Clone> Context<T> { | 230 | impl Context { |
149 | /// Get a reference to the context's data. | 231 | /// Get a reference to the context's data. |
150 | pub(crate) fn data(&self) -> &T { | 232 | pub(crate) fn $0data(&self) -> &Data { |
151 | &self.data | 233 | &self.data |
152 | } | 234 | } |
153 | }"#, | 235 | } |
236 | "#, | ||
154 | ); | 237 | ); |
155 | } | 238 | } |
156 | 239 | ||
@@ -159,34 +242,36 @@ impl<T: Clone> Context<T> { | |||
159 | check_assist( | 242 | check_assist( |
160 | generate_getter, | 243 | generate_getter, |
161 | r#" | 244 | r#" |
162 | struct Context<T: Clone> { | 245 | struct Context { |
163 | data: T, | 246 | data: Data, |
164 | cou$0nt: usize, | 247 | cou$0nt: usize, |
165 | } | 248 | } |
166 | 249 | ||
167 | impl<T: Clone> Context<T> { | 250 | impl Context { |
168 | /// Get a reference to the context's data. | 251 | /// Get a reference to the context's data. |
169 | fn data(&self) -> &T { | 252 | fn data(&self) -> &Data { |
170 | &self.data | 253 | &self.data |
171 | } | 254 | } |
172 | }"#, | 255 | } |
256 | "#, | ||
173 | r#" | 257 | r#" |
174 | struct Context<T: Clone> { | 258 | struct Context { |
175 | data: T, | 259 | data: Data, |
176 | count: usize, | 260 | count: usize, |
177 | } | 261 | } |
178 | 262 | ||
179 | impl<T: Clone> Context<T> { | 263 | impl Context { |
180 | /// Get a reference to the context's data. | 264 | /// Get a reference to the context's data. |
181 | fn data(&self) -> &T { | 265 | fn data(&self) -> &Data { |
182 | &self.data | 266 | &self.data |
183 | } | 267 | } |
184 | 268 | ||
185 | /// Get a reference to the context's count. | 269 | /// Get a reference to the context's count. |
186 | fn count(&self) -> &usize { | 270 | fn $0count(&self) -> &usize { |
187 | &self.count | 271 | &self.count |
188 | } | 272 | } |
189 | }"#, | 273 | } |
274 | "#, | ||
190 | ); | 275 | ); |
191 | } | 276 | } |
192 | } | 277 | } |
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 | } | ||