aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs91
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 @@
1use crate::{ 1use crate::{
2 assist_context::{AssistContext, Assists}, 2 assist_context::{AssistContext, Assists},
3 AssistId, 3 utils, AssistId,
4}; 4};
5use syntax::{ 5use syntax::{
6 ast::{self, NameOwner}, 6 ast::{self, Adt, Impl, NameOwner},
7 AstNode, SyntaxKind, SyntaxNode, SyntaxText, 7 AstNode, Direction,
8}; 8};
9use test_utils::mark; 9use test_utils::mark;
10 10
@@ -38,54 +38,50 @@ use test_utils::mark;
38// } 38// }
39// ``` 39// ```
40pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 40pub(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
73fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option<SyntaxNode> { 71fn 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
77fn default_fn_node_for_new(struct_name: SyntaxText) -> String {
78 // FIXME: Update the implementation to consider the code indentation.
79 format!(
80 r#"
81
82impl 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#"
232struct Example { _inner: () }
233struct Test { value: u32 }
234
235impl Example {
236 pub fn new$0 () -> Self {
237 Self { _inner: () }
238 }
239}
240"#,
241 r#"
242struct Example { _inner: () }
243struct Test { value: u32 }
244
245impl Example {
246 pub fn new () -> Self {
247 Self { _inner: () }
248 }
249}
250
251impl Default for Example {
252 fn default() -> Self {
253 Self::new()
254 }
255}
256"#,
257 );
258 }
230} 259}