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