]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/generate_default_from_new.rs
7708: Initial implementation of generate Default assist.
[rust.git] / crates / ide_assists / src / handlers / generate_default_from_new.rs
1 use crate::{AssistId, assist_context::{AssistContext, Assists}};
2 use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxText, ast::{self, NameOwner}};
3 use test_utils::mark;
4
5 // Assist: generate_default_from_new
6 //
7 // Generates default implementation from new method
8 //
9 // ```
10 // struct Example { _inner: () }
11 //
12 // impl Example {
13 //     pu|b fn new() -> Self {
14 //         Self { _inner: () }
15 //     }
16 // }
17 // ```
18 // ->
19 // ```
20 // struct Example { _inner: () }
21
22 // impl Example {
23 //     pub fn new() -> Self {
24 //         Self { _inner: () }
25 //     }
26 // }
27
28 // impl Default for Example {
29 //     fn default() -> Self {
30 //         Self::new()
31 //     }
32 // }
33 // ```
34 pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
35     let fn_node: ast::Fn = ctx.find_node_at_offset()?;
36     let fn_name = fn_node.name()?.to_string();
37
38     if !fn_name.eq("new") {
39         mark::hit!(other_function_than_new);
40         return None;
41     }
42
43     if fn_node.param_list()?.params().count() != 0 {
44         mark::hit!(new_function_with_parameters);
45         return None;
46     }
47
48     let insert_after = scope_for_fn_insertion_node(&fn_node.syntax())?;
49     let impl_obj = ast::Impl::cast(insert_after)?;
50     let struct_name = impl_obj.self_ty()?.syntax().text();
51
52     let default_fn_syntax = default_fn_node_for_new(struct_name);
53
54
55     acc.add(
56         AssistId("generate_default_from_new", crate::AssistKind::Generate),
57         "Generate a Default impl from a new fn",
58         impl_obj.syntax().text_range(),
59         move |builder| {
60             // TODO: indentation logic can also go here.
61             // let new_indent = IndentLevel::from_node(&insert_after);
62             let insert_location = impl_obj.syntax().text_range().end();
63             builder.insert(insert_location, default_fn_syntax);
64         },
65     )
66 }
67
68 fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option<SyntaxNode> {
69     node.ancestors().into_iter().find(|node| node.kind() == SyntaxKind::IMPL)
70 }
71
72 fn default_fn_node_for_new(struct_name: SyntaxText) -> String {
73     // TODO: Update the implementation to consider the code indentation.
74     format!(
75     r#"
76
77 impl Default for {} {{
78     fn default() -> Self {{
79         Self::new()
80     }}
81 }}"#
82     ,struct_name)
83 }
84
85 #[cfg(test)]
86 mod tests {
87     use crate::tests::{check_assist, check_assist_not_applicable};
88
89     use super::*;
90
91     #[test]
92     fn generate_default() {
93         check_assist(
94             generate_default_from_new,
95             r#"
96 struct Example { _inner: () }
97
98 impl Example {
99     pub fn ne$0w() -> Self {
100         Self { _inner: () }
101     }
102 }
103
104 fn main() {}
105 "#,
106             r#"
107 struct Example { _inner: () }
108
109 impl Example {
110     pub fn new() -> Self {
111         Self { _inner: () }
112     }
113 }
114
115 impl Default for Example {
116     fn default() -> Self {
117         Self::new()
118     }
119 }
120
121 fn main() {}
122 "#,
123         );
124     }
125
126     #[test]
127     fn generate_default2() {
128         check_assist(
129             generate_default_from_new,
130             r#"
131 struct Test { value: u32 }
132
133 impl Test {
134     pub fn ne$0w() -> Self {
135         Self { value: 0 }
136     }
137 }
138 "#,
139             r#"
140 struct Test { value: u32 }
141
142 impl Test {
143     pub fn new() -> Self {
144         Self { value: 0 }
145     }
146 }
147
148 impl Default for Test {
149     fn default() -> Self {
150         Self::new()
151     }
152 }
153 "#,
154         );
155     }
156
157     #[test]
158     fn new_function_with_parameters() {
159         mark::check!(new_function_with_parameters);
160         check_assist_not_applicable(generate_default_from_new,
161         r#"
162 struct Example { _inner: () }
163
164 impl Example {
165     pub fn $0new(value: ()) -> Self {
166         Self { _inner: value }
167     }
168 }
169 "#
170         );
171     }
172
173     #[test]
174     fn other_function_than_new() {
175         mark::check!(other_function_than_new);
176         check_assist_not_applicable(generate_default_from_new,
177         r#"
178 struct Example { _inner: () }
179
180 impl Exmaple {
181     pub fn a$0dd() -> Self {
182         Self { _inner: () }
183     }
184 }
185
186 "#
187         );
188     }
189
190 //     #[test]
191 //     fn default_block_is_already_present() {
192 //         check_assist_not_applicable(generate_default_from_new,
193 //         r#"
194 // struct Example { _inner: () }
195
196 // impl Exmaple {
197 //     pub fn n$0ew() -> Self {
198 //         Self { _inner: () }
199 //     }
200 // }
201
202 // impl Default for Example {
203 //     fn default() -> Self {
204 //         Self::new()
205 //     }
206 // }
207 // "#,
208 //         );
209 //     }
210
211     #[test]
212     fn standalone_new_function() {
213         check_assist_not_applicable(generate_default_from_new,
214         r#"
215 fn n$0ew() -> u32 {
216     0
217 }
218 "#
219         );
220     }
221 }