aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-12 17:16:02 +0000
committerGitHub <[email protected]>2021-02-12 17:16:02 +0000
commit4d51b5644458c7dcb97a4d445f1b379cd2548a78 (patch)
treee67df57ec40bd510028d0002306debd8c73f61b8
parent29bc6b45fbcefc3369c14035126a8b0510b2ef60 (diff)
parentac959b82b3408fafd22f4fbb59e10383a18c545f (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.rs41
-rw-r--r--crates/assists/src/handlers/generate_getter.rs40
-rw-r--r--crates/assists/src/handlers/generate_getter_mut.rs40
-rw-r--r--crates/assists/src/handlers/generate_new.rs4
-rw-r--r--crates/assists/src/handlers/generate_setter.rs40
-rw-r--r--crates/assists/src/utils.rs24
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};
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::{ 6use 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#"
209enum Variant {
210 Undefined,
211 Minor,
212 Major$0,
213}
214
215impl 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
227impl 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;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4 4
5use crate::{ 5use 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#"
162struct Context<T: Clone> {
163 data: T,
164 cou$0nt: usize,
165}
166
167impl<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#"
174struct Context<T: Clone> {
175 data: T,
176 count: usize,
177}
178
179impl<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;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4 4
5use crate::{ 5use 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#"
165struct Context<T: Clone> {
166 data: T,
167 cou$0nt: usize,
168}
169
170impl<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#"
177struct Context<T: Clone> {
178 data: T,
179 count: usize,
180}
181
182impl<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;
4use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner}; 4use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner};
5 5
6use crate::{ 6use 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;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4 4
5use crate::{ 5use 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#"
168struct Context<T: Clone> {
169 data: T,
170 cou$0nt: usize,
171}
172
173impl<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#"
180struct Context<T: Clone> {
181 data: T,
182 count: usize,
183}
184
185impl<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_*`
283pub(crate) fn find_struct_impl( 283pub(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`
348pub(crate) fn find_impl_block(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> { 347pub(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`
356pub(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