diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/generate_default_from_new.rs | 91 |
1 files changed, 60 insertions, 31 deletions
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index c7b049a46..b4f80fec9 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | assist_context::{AssistContext, Assists}, | 2 | assist_context::{AssistContext, Assists}, |
3 | AssistId, | 3 | utils, AssistId, |
4 | }; | 4 | }; |
5 | use syntax::{ | 5 | use syntax::{ |
6 | ast::{self, NameOwner}, | 6 | ast::{self, Adt, Impl, NameOwner}, |
7 | AstNode, SyntaxKind, SyntaxNode, SyntaxText, | 7 | AstNode, Direction, |
8 | }; | 8 | }; |
9 | use test_utils::mark; | 9 | use test_utils::mark; |
10 | 10 | ||
@@ -38,54 +38,50 @@ use test_utils::mark; | |||
38 | // } | 38 | // } |
39 | // ``` | 39 | // ``` |
40 | pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 40 | pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
41 | let fn_node: ast::Fn = ctx.find_node_at_offset()?; | 41 | let fn_node = ctx.find_node_at_offset::<ast::Fn>()?; |
42 | let fn_name = fn_node.name()?.to_string(); | 42 | let fn_name = fn_node.name()?; |
43 | 43 | ||
44 | if !fn_name.eq("new") { | 44 | if fn_name.text() != "new" { |
45 | mark::hit!(other_function_than_new); | 45 | mark::hit!(other_function_than_new); |
46 | return None; | 46 | return None; |
47 | } | 47 | } |
48 | 48 | ||
49 | if fn_node.param_list()?.params().count() != 0 { | 49 | if fn_node.param_list()?.params().next().is_some() { |
50 | mark::hit!(new_function_with_parameters); | 50 | mark::hit!(new_function_with_parameters); |
51 | return None; | 51 | return None; |
52 | } | 52 | } |
53 | 53 | ||
54 | let insert_after = scope_for_fn_insertion_node(&fn_node.syntax())?; | 54 | let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; |
55 | let impl_obj = ast::Impl::cast(insert_after)?; | ||
56 | let struct_name = impl_obj.self_ty()?.syntax().text(); | ||
57 | 55 | ||
58 | let default_fn_syntax = default_fn_node_for_new(struct_name); | 56 | let insert_location = impl_.syntax().text_range(); |
59 | 57 | ||
60 | acc.add( | 58 | acc.add( |
61 | AssistId("generate_default_from_new", crate::AssistKind::Generate), | 59 | AssistId("generate_default_from_new", crate::AssistKind::Generate), |
62 | "Generate a Default impl from a new fn", | 60 | "Generate a Default impl from a new fn", |
63 | impl_obj.syntax().text_range(), | 61 | insert_location, |
64 | move |builder| { | 62 | move |builder| { |
65 | // FIXME: indentation logic can also go here. | 63 | let default_fn_syntax = default_fn_node_for_new(impl_); |
66 | // let new_indent = IndentLevel::from_node(&insert_after); | 64 | if let Some(code) = default_fn_syntax { |
67 | let insert_location = impl_obj.syntax().text_range().end(); | 65 | builder.insert(insert_location.end(), code) |
68 | builder.insert(insert_location, default_fn_syntax); | 66 | } |
69 | }, | 67 | }, |
70 | ) | 68 | ) |
71 | } | 69 | } |
72 | 70 | ||
73 | fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option<SyntaxNode> { | 71 | fn default_fn_node_for_new(impl_: Impl) -> Option<String> { |
74 | node.ancestors().into_iter().find(|node| node.kind() == SyntaxKind::IMPL) | 72 | // the code string is this way due to formatting reason |
75 | } | 73 | let code = r#" fn default() -> Self { |
76 | |||
77 | fn default_fn_node_for_new(struct_name: SyntaxText) -> String { | ||
78 | // FIXME: Update the implementation to consider the code indentation. | ||
79 | format!( | ||
80 | r#" | ||
81 | |||
82 | impl Default for {} {{ | ||
83 | fn default() -> Self {{ | ||
84 | Self::new() | 74 | Self::new() |
85 | }} | 75 | }"#; |
86 | }}"#, | 76 | let struct_name = impl_.self_ty()?.syntax().to_string(); |
87 | struct_name | 77 | let struct_ = impl_ |
88 | ) | 78 | .syntax() |
79 | .siblings(Direction::Prev) | ||
80 | .filter_map(ast::Struct::cast) | ||
81 | .find(|struct_| struct_.name().unwrap().text() == struct_name)?; | ||
82 | |||
83 | let adt = Adt::cast(struct_.syntax().clone())?; | ||
84 | Some(utils::generate_trait_impl_text(&adt, "Default", code)) | ||
89 | } | 85 | } |
90 | 86 | ||
91 | #[cfg(test)] | 87 | #[cfg(test)] |
@@ -227,4 +223,37 @@ fn n$0ew() -> u32 { | |||
227 | "#, | 223 | "#, |
228 | ); | 224 | ); |
229 | } | 225 | } |
226 | |||
227 | #[test] | ||
228 | fn multiple_struct_blocks() { | ||
229 | check_assist( | ||
230 | generate_default_from_new, | ||
231 | r#" | ||
232 | struct Example { _inner: () } | ||
233 | struct Test { value: u32 } | ||
234 | |||
235 | impl Example { | ||
236 | pub fn new$0 () -> Self { | ||
237 | Self { _inner: () } | ||
238 | } | ||
239 | } | ||
240 | "#, | ||
241 | r#" | ||
242 | struct Example { _inner: () } | ||
243 | struct Test { value: u32 } | ||
244 | |||
245 | impl Example { | ||
246 | pub fn new () -> Self { | ||
247 | Self { _inner: () } | ||
248 | } | ||
249 | } | ||
250 | |||
251 | impl Default for Example { | ||
252 | fn default() -> Self { | ||
253 | Self::new() | ||
254 | } | ||
255 | } | ||
256 | "#, | ||
257 | ); | ||
258 | } | ||
230 | } | 259 | } |