|
1 | 1 | use crate::{
|
2 | 2 | assist_context::{AssistContext, Assists},
|
3 |
| - AssistId, |
| 3 | + utils, AssistId, |
4 | 4 | };
|
5 | 5 | use syntax::{
|
6 |
| - ast::{self, NameOwner}, |
7 |
| - AstNode, SyntaxKind, SyntaxNode, SyntaxText, |
| 6 | + ast::{self, Adt, Impl, NameOwner}, |
| 7 | + AstNode, Direction, |
8 | 8 | };
|
9 | 9 | use test_utils::mark;
|
10 | 10 |
|
@@ -38,54 +38,50 @@ use test_utils::mark;
|
38 | 38 | // }
|
39 | 39 | // ```
|
40 | 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()?; |
42 |
| - let fn_name = fn_node.name()?.to_string(); |
| 41 | + let fn_node = ctx.find_node_at_offset::<ast::Fn>()?; |
| 42 | + let fn_name = fn_node.name()?; |
43 | 43 |
|
44 |
| - if !fn_name.eq("new") { |
| 44 | + if fn_name.text() != "new" { |
45 | 45 | mark::hit!(other_function_than_new);
|
46 | 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 | 50 | mark::hit!(new_function_with_parameters);
|
51 | 51 | return None;
|
52 | 52 | }
|
53 | 53 |
|
54 |
| - let insert_after = scope_for_fn_insertion_node(&fn_node.syntax())?; |
55 |
| - let impl_obj = ast::Impl::cast(insert_after)?; |
56 |
| - let struct_name = impl_obj.self_ty()?.syntax().text(); |
| 54 | + let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; |
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 | 58 | acc.add(
|
61 | 59 | AssistId("generate_default_from_new", crate::AssistKind::Generate),
|
62 | 60 | "Generate a Default impl from a new fn",
|
63 |
| - impl_obj.syntax().text_range(), |
| 61 | + insert_location, |
64 | 62 | move |builder| {
|
65 |
| - // FIXME: indentation logic can also go here. |
66 |
| - // let new_indent = IndentLevel::from_node(&insert_after); |
67 |
| - let insert_location = impl_obj.syntax().text_range().end(); |
68 |
| - builder.insert(insert_location, default_fn_syntax); |
| 63 | + let default_fn_syntax = default_fn_node_for_new(impl_); |
| 64 | + if let Some(code) = default_fn_syntax { |
| 65 | + builder.insert(insert_location.end(), code) |
| 66 | + } |
69 | 67 | },
|
70 | 68 | )
|
71 | 69 | }
|
72 | 70 |
|
73 |
| -fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option<SyntaxNode> { |
74 |
| - node.ancestors().into_iter().find(|node| node.kind() == SyntaxKind::IMPL) |
75 |
| -} |
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 {{ |
| 71 | +fn default_fn_node_for_new(impl_: Impl) -> Option<String> { |
| 72 | + // the code string is this way due to formatting reason |
| 73 | + let code = r#" fn default() -> Self { |
84 | 74 | Self::new()
|
85 |
| - }} |
86 |
| -}}"#, |
87 |
| - struct_name |
88 |
| - ) |
| 75 | + }"#; |
| 76 | + let struct_name = impl_.self_ty()?.syntax().to_string(); |
| 77 | + let struct_ = impl_ |
| 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 | 87 | #[cfg(test)]
|
@@ -224,6 +220,39 @@ impl Exmaple {
|
224 | 220 | fn n$0ew() -> u32 {
|
225 | 221 | 0
|
226 | 222 | }
|
| 223 | +"#, |
| 224 | + ); |
| 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 | +} |
227 | 256 | "#,
|
228 | 257 | );
|
229 | 258 | }
|
|
0 commit comments