diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-02-12 17:16:02 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-12 17:16:02 +0000 |
commit | 4d51b5644458c7dcb97a4d445f1b379cd2548a78 (patch) | |
tree | e67df57ec40bd510028d0002306debd8c73f61b8 | |
parent | 29bc6b45fbcefc3369c14035126a8b0510b2ef60 (diff) | |
parent | ac959b82b3408fafd22f4fbb59e10383a18c545f (diff) |
Merge #7650
7650: Add `find_impl_block_end` assist helper r=Veykril a=yoshuawuyts
Fixes #7605. This makes it so assists can use helpers to either append a method to the start or the end of an `impl` block. Thanks!
@Veykril if this is merged, perhaps it could be good to update the gif in https://github.com/rust-analyzer/rust-analyzer/pull/7617#issuecomment-776622135 ? -- this should fix the ordering issue when generating multiple methods.
Co-authored-by: Yoshua Wuyts <[email protected]>
-rw-r--r-- | crates/assists/src/handlers/generate_enum_match_method.rs | 41 | ||||
-rw-r--r-- | crates/assists/src/handlers/generate_getter.rs | 40 | ||||
-rw-r--r-- | crates/assists/src/handlers/generate_getter_mut.rs | 40 | ||||
-rw-r--r-- | crates/assists/src/handlers/generate_new.rs | 4 | ||||
-rw-r--r-- | crates/assists/src/handlers/generate_setter.rs | 40 | ||||
-rw-r--r-- | crates/assists/src/utils.rs | 24 |
6 files changed, 171 insertions, 18 deletions
diff --git a/crates/assists/src/handlers/generate_enum_match_method.rs b/crates/assists/src/handlers/generate_enum_match_method.rs index c3ff38b66..aeb887e71 100644 --- a/crates/assists/src/handlers/generate_enum_match_method.rs +++ b/crates/assists/src/handlers/generate_enum_match_method.rs | |||
@@ -4,7 +4,7 @@ use syntax::ast::{self, AstNode, NameOwner}; | |||
4 | use test_utils::mark; | 4 | use test_utils::mark; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | utils::{find_impl_block, find_struct_impl, generate_impl_text}, | 7 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
8 | AssistContext, AssistId, AssistKind, Assists, | 8 | AssistContext, AssistId, AssistKind, Assists, |
9 | }; | 9 | }; |
10 | 10 | ||
@@ -80,7 +80,7 @@ pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext) | |||
80 | ); | 80 | ); |
81 | 81 | ||
82 | let start_offset = impl_def | 82 | let start_offset = impl_def |
83 | .and_then(|impl_def| find_impl_block(impl_def, &mut buf)) | 83 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) |
84 | .unwrap_or_else(|| { | 84 | .unwrap_or_else(|| { |
85 | buf = generate_impl_text(&ast::Adt::Enum(parent_enum.clone()), &buf); | 85 | buf = generate_impl_text(&ast::Adt::Enum(parent_enum.clone()), &buf); |
86 | parent_enum.syntax().text_range().end() | 86 | parent_enum.syntax().text_range().end() |
@@ -200,4 +200,41 @@ impl Variant { | |||
200 | }"#, | 200 | }"#, |
201 | ); | 201 | ); |
202 | } | 202 | } |
203 | |||
204 | #[test] | ||
205 | fn test_multiple_generate_enum_match_from_variant() { | ||
206 | check_assist( | ||
207 | generate_enum_match_method, | ||
208 | r#" | ||
209 | enum Variant { | ||
210 | Undefined, | ||
211 | Minor, | ||
212 | Major$0, | ||
213 | } | ||
214 | |||
215 | impl Variant { | ||
216 | /// Returns `true` if the variant is [`Minor`]. | ||
217 | fn is_minor(&self) -> bool { | ||
218 | matches!(self, Self::Minor) | ||
219 | } | ||
220 | }"#, | ||
221 | r#"enum Variant { | ||
222 | Undefined, | ||
223 | Minor, | ||
224 | Major, | ||
225 | } | ||
226 | |||
227 | impl Variant { | ||
228 | /// Returns `true` if the variant is [`Minor`]. | ||
229 | fn is_minor(&self) -> bool { | ||
230 | matches!(self, Self::Minor) | ||
231 | } | ||
232 | |||
233 | /// Returns `true` if the variant is [`Major`]. | ||
234 | fn is_major(&self) -> bool { | ||
235 | matches!(self, Self::Major) | ||
236 | } | ||
237 | }"#, | ||
238 | ); | ||
239 | } | ||
203 | } | 240 | } |
diff --git a/crates/assists/src/handlers/generate_getter.rs b/crates/assists/src/handlers/generate_getter.rs index b63dfce41..fbcf8b069 100644 --- a/crates/assists/src/handlers/generate_getter.rs +++ b/crates/assists/src/handlers/generate_getter.rs | |||
@@ -3,7 +3,7 @@ use syntax::ast::VisibilityOwner; | |||
3 | use syntax::ast::{self, AstNode, NameOwner}; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | utils::{find_impl_block, find_struct_impl, generate_impl_text}, | 6 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
7 | AssistContext, AssistId, AssistKind, Assists, | 7 | AssistContext, AssistId, AssistKind, Assists, |
8 | }; | 8 | }; |
9 | 9 | ||
@@ -73,7 +73,7 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
73 | ); | 73 | ); |
74 | 74 | ||
75 | let start_offset = impl_def | 75 | let start_offset = impl_def |
76 | .and_then(|impl_def| find_impl_block(impl_def, &mut buf)) | 76 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) |
77 | .unwrap_or_else(|| { | 77 | .unwrap_or_else(|| { |
78 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); | 78 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); |
79 | strukt.syntax().text_range().end() | 79 | strukt.syntax().text_range().end() |
@@ -153,4 +153,40 @@ impl<T: Clone> Context<T> { | |||
153 | }"#, | 153 | }"#, |
154 | ); | 154 | ); |
155 | } | 155 | } |
156 | |||
157 | #[test] | ||
158 | fn test_multiple_generate_getter() { | ||
159 | check_assist( | ||
160 | generate_getter, | ||
161 | r#" | ||
162 | struct Context<T: Clone> { | ||
163 | data: T, | ||
164 | cou$0nt: usize, | ||
165 | } | ||
166 | |||
167 | impl<T: Clone> Context<T> { | ||
168 | /// Get a reference to the context's data. | ||
169 | fn data(&self) -> &T { | ||
170 | &self.data | ||
171 | } | ||
172 | }"#, | ||
173 | r#" | ||
174 | struct Context<T: Clone> { | ||
175 | data: T, | ||
176 | count: usize, | ||
177 | } | ||
178 | |||
179 | impl<T: Clone> Context<T> { | ||
180 | /// Get a reference to the context's data. | ||
181 | fn data(&self) -> &T { | ||
182 | &self.data | ||
183 | } | ||
184 | |||
185 | /// Get a reference to the context's count. | ||
186 | fn count(&self) -> &usize { | ||
187 | &self.count | ||
188 | } | ||
189 | }"#, | ||
190 | ); | ||
191 | } | ||
156 | } | 192 | } |
diff --git a/crates/assists/src/handlers/generate_getter_mut.rs b/crates/assists/src/handlers/generate_getter_mut.rs index b5085035e..bf0d99881 100644 --- a/crates/assists/src/handlers/generate_getter_mut.rs +++ b/crates/assists/src/handlers/generate_getter_mut.rs | |||
@@ -3,7 +3,7 @@ use syntax::ast::VisibilityOwner; | |||
3 | use syntax::ast::{self, AstNode, NameOwner}; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | utils::{find_impl_block, find_struct_impl, generate_impl_text}, | 6 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
7 | AssistContext, AssistId, AssistKind, Assists, | 7 | AssistContext, AssistId, AssistKind, Assists, |
8 | }; | 8 | }; |
9 | 9 | ||
@@ -76,7 +76,7 @@ pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
76 | ); | 76 | ); |
77 | 77 | ||
78 | let start_offset = impl_def | 78 | let start_offset = impl_def |
79 | .and_then(|impl_def| find_impl_block(impl_def, &mut buf)) | 79 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) |
80 | .unwrap_or_else(|| { | 80 | .unwrap_or_else(|| { |
81 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); | 81 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); |
82 | strukt.syntax().text_range().end() | 82 | strukt.syntax().text_range().end() |
@@ -156,4 +156,40 @@ impl<T: Clone> Context<T> { | |||
156 | }"#, | 156 | }"#, |
157 | ); | 157 | ); |
158 | } | 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 | } | ||
159 | } | 195 | } |
diff --git a/crates/assists/src/handlers/generate_new.rs b/crates/assists/src/handlers/generate_new.rs index c29077225..8ce5930b7 100644 --- a/crates/assists/src/handlers/generate_new.rs +++ b/crates/assists/src/handlers/generate_new.rs | |||
@@ -4,7 +4,7 @@ use stdx::format_to; | |||
4 | use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner}; | 4 | use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | utils::{find_impl_block, find_struct_impl, generate_impl_text}, | 7 | utils::{find_impl_block_start, find_struct_impl, generate_impl_text}, |
8 | AssistContext, AssistId, AssistKind, Assists, | 8 | AssistContext, AssistId, AssistKind, Assists, |
9 | }; | 9 | }; |
10 | 10 | ||
@@ -58,7 +58,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
58 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); | 58 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); |
59 | 59 | ||
60 | let start_offset = impl_def | 60 | let start_offset = impl_def |
61 | .and_then(|impl_def| find_impl_block(impl_def, &mut buf)) | 61 | .and_then(|impl_def| find_impl_block_start(impl_def, &mut buf)) |
62 | .unwrap_or_else(|| { | 62 | .unwrap_or_else(|| { |
63 | buf = generate_impl_text(&Adt::Struct(strukt.clone()), &buf); | 63 | buf = generate_impl_text(&Adt::Struct(strukt.clone()), &buf); |
64 | strukt.syntax().text_range().end() | 64 | strukt.syntax().text_range().end() |
diff --git a/crates/assists/src/handlers/generate_setter.rs b/crates/assists/src/handlers/generate_setter.rs index c9043a162..b655f9b9c 100644 --- a/crates/assists/src/handlers/generate_setter.rs +++ b/crates/assists/src/handlers/generate_setter.rs | |||
@@ -3,7 +3,7 @@ use syntax::ast::VisibilityOwner; | |||
3 | use syntax::ast::{self, AstNode, NameOwner}; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | utils::{find_impl_block, find_struct_impl, generate_impl_text}, | 6 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, |
7 | AssistContext, AssistId, AssistKind, Assists, | 7 | AssistContext, AssistId, AssistKind, Assists, |
8 | }; | 8 | }; |
9 | 9 | ||
@@ -79,7 +79,7 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
79 | ); | 79 | ); |
80 | 80 | ||
81 | let start_offset = impl_def | 81 | let start_offset = impl_def |
82 | .and_then(|impl_def| find_impl_block(impl_def, &mut buf)) | 82 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) |
83 | .unwrap_or_else(|| { | 83 | .unwrap_or_else(|| { |
84 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); | 84 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); |
85 | strukt.syntax().text_range().end() | 85 | strukt.syntax().text_range().end() |
@@ -159,4 +159,40 @@ impl<T: Clone> Person<T> { | |||
159 | }"#, | 159 | }"#, |
160 | ); | 160 | ); |
161 | } | 161 | } |
162 | |||
163 | #[test] | ||
164 | fn test_multiple_generate_setter() { | ||
165 | check_assist( | ||
166 | generate_setter, | ||
167 | r#" | ||
168 | struct Context<T: Clone> { | ||
169 | data: T, | ||
170 | cou$0nt: usize, | ||
171 | } | ||
172 | |||
173 | impl<T: Clone> Context<T> { | ||
174 | /// Set the context's data. | ||
175 | fn set_data(&mut self, data: T) { | ||
176 | self.data = data; | ||
177 | } | ||
178 | }"#, | ||
179 | r#" | ||
180 | struct Context<T: Clone> { | ||
181 | data: T, | ||
182 | count: usize, | ||
183 | } | ||
184 | |||
185 | impl<T: Clone> Context<T> { | ||
186 | /// Set the context's data. | ||
187 | fn set_data(&mut self, data: T) { | ||
188 | self.data = data; | ||
189 | } | ||
190 | |||
191 | /// Set the context's count. | ||
192 | fn set_count(&mut self, count: usize) { | ||
193 | self.count = count; | ||
194 | } | ||
195 | }"#, | ||
196 | ); | ||
197 | } | ||
162 | } | 198 | } |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 643dade23..5dd32aef1 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -279,7 +279,7 @@ pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool { | |||
279 | // | 279 | // |
280 | // FIXME: change the new fn checking to a more semantic approach when that's more | 280 | // FIXME: change the new fn checking to a more semantic approach when that's more |
281 | // viable (e.g. we process proc macros, etc) | 281 | // viable (e.g. we process proc macros, etc) |
282 | // FIXME: this partially overlaps with `find_impl_block` | 282 | // FIXME: this partially overlaps with `find_impl_block_*` |
283 | pub(crate) fn find_struct_impl( | 283 | pub(crate) fn find_struct_impl( |
284 | ctx: &AssistContext, | 284 | ctx: &AssistContext, |
285 | strukt: &ast::Adt, | 285 | strukt: &ast::Adt, |
@@ -343,17 +343,25 @@ fn has_fn(imp: &ast::Impl, rhs_name: &str) -> bool { | |||
343 | 343 | ||
344 | /// Find the start of the `impl` block for the given `ast::Impl`. | 344 | /// Find the start of the `impl` block for the given `ast::Impl`. |
345 | // | 345 | // |
346 | // FIXME: add a way to find the end of the `impl` block. | ||
347 | // FIXME: this partially overlaps with `find_struct_impl` | 346 | // FIXME: this partially overlaps with `find_struct_impl` |
348 | pub(crate) fn find_impl_block(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> { | 347 | pub(crate) fn find_impl_block_start(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> { |
349 | buf.push('\n'); | 348 | buf.push('\n'); |
350 | let start = impl_def | 349 | let start = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())?.text_range().end(); |
351 | .syntax() | 350 | Some(start) |
352 | .descendants_with_tokens() | 351 | } |
353 | .find(|t| t.kind() == T!['{'])? | 352 | |
353 | /// Find the end of the `impl` block for the given `ast::Impl`. | ||
354 | // | ||
355 | // FIXME: this partially overlaps with `find_struct_impl` | ||
356 | pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> { | ||
357 | buf.push('\n'); | ||
358 | let end = impl_def | ||
359 | .assoc_item_list() | ||
360 | .and_then(|it| it.r_curly_token())? | ||
361 | .prev_sibling_or_token()? | ||
354 | .text_range() | 362 | .text_range() |
355 | .end(); | 363 | .end(); |
356 | Some(start) | 364 | Some(end) |
357 | } | 365 | } |
358 | 366 | ||
359 | // Generates the surrounding `impl Type { <code> }` including type and lifetime | 367 | // Generates the surrounding `impl Type { <code> }` including type and lifetime |