@@ -34,7 +34,7 @@ pub(crate) fn convert_nested_function_to_closure(
3434 let name = ctx. find_node_at_offset :: < ast:: Name > ( ) ?;
3535 let function = name. syntax ( ) . parent ( ) . and_then ( ast:: Fn :: cast) ?;
3636
37- if !is_nested_function ( & function) || is_generic ( & function) {
37+ if !is_nested_function ( & function) || is_generic ( & function) || has_modifiers ( & function ) {
3838 return None ;
3939 }
4040
@@ -43,21 +43,21 @@ pub(crate) fn convert_nested_function_to_closure(
4343 let name = function. name ( ) ?;
4444 let params = function. param_list ( ) ?;
4545
46+ let params_text = params. syntax ( ) . text ( ) . to_string ( ) ;
47+ let closure_params = params_text. strip_prefix ( "(" ) . and_then ( |p| p. strip_suffix ( ")" ) ) ?;
48+
4649 acc. add (
4750 AssistId ( "convert_nested_function_to_closure" , AssistKind :: RefactorRewrite ) ,
4851 "Convert nested function to closure" ,
4952 target,
5053 |edit| {
5154 let has_semicolon = has_semicolon ( & function) ;
52- let params_text = params. syntax ( ) . text ( ) . to_string ( ) ;
53- let params_text_trimmed =
54- params_text. strip_prefix ( "(" ) . and_then ( |p| p. strip_suffix ( ")" ) ) ;
55-
56- if let Some ( closure_params) = params_text_trimmed {
57- let body = body. to_string ( ) ;
58- let body = if has_semicolon { body } else { format ! ( "{};" , body) } ;
59- edit. replace ( target, format ! ( "let {} = |{}| {}" , name, closure_params, body) ) ;
55+
56+ let mut body = body. to_string ( ) ;
57+ if !has_semicolon {
58+ body. push ( ';' ) ;
6059 }
60+ edit. replace ( target, format ! ( "let {} = |{}| {}" , name, closure_params, body) ) ;
6161 } ,
6262 )
6363}
@@ -77,6 +77,17 @@ fn is_generic(function: &ast::Fn) -> bool {
7777 function. generic_param_list ( ) . is_some ( )
7878}
7979
80+ /// Returns whether the given nested function has any modifiers:
81+ ///
82+ /// - `async`,
83+ /// - `const` or
84+ /// - `unsafe`
85+ fn has_modifiers ( function : & ast:: Fn ) -> bool {
86+ function. async_token ( ) . is_some ( )
87+ || function. const_token ( ) . is_some ( )
88+ || function. unsafe_token ( ) . is_some ( )
89+ }
90+
8091/// Returns whether the given nested function has a trailing semicolon.
8192fn has_semicolon ( function : & ast:: Fn ) -> bool {
8293 function
@@ -143,7 +154,7 @@ fn main() {
143154 }
144155
145156 #[ test]
146- fn convert_nested_function_to_closure_does_not_work_on_top_level_function ( ) {
157+ fn convert_nested_function_to_closure_is_not_suggested_on_top_level_function ( ) {
147158 check_assist_not_applicable (
148159 convert_nested_function_to_closure,
149160 r#"
@@ -153,14 +164,14 @@ fn ma$0in() {}
153164 }
154165
155166 #[ test]
156- fn convert_nested_function_to_closure_does_not_work_when_cursor_off_name ( ) {
167+ fn convert_nested_function_to_closure_is_not_suggested_when_cursor_off_name ( ) {
157168 check_assist_not_applicable (
158169 convert_nested_function_to_closure,
159170 r#"
160171fn main() {
161172 fn foo(a: u64, $0b: u64) -> u64 {
162173 2 * (a + b)
163- };
174+ }
164175
165176 _ = foo(3, 4);
166177}
@@ -169,14 +180,30 @@ fn main() {
169180 }
170181
171182 #[ test]
172- fn convert_nested_function_to_closure_does_not_work_if_function_has_generic_params ( ) {
183+ fn convert_nested_function_to_closure_is_not_suggested_if_function_has_generic_params ( ) {
173184 check_assist_not_applicable (
174185 convert_nested_function_to_closure,
175186 r#"
176187fn main() {
177188 fn fo$0o<S: Into<String>>(s: S) -> String {
178189 s.into()
179- };
190+ }
191+
192+ _ = foo("hello");
193+ }
194+ "# ,
195+ ) ;
196+ }
197+
198+ #[ test]
199+ fn convert_nested_function_to_closure_is_not_suggested_if_function_has_modifier ( ) {
200+ check_assist_not_applicable (
201+ convert_nested_function_to_closure,
202+ r#"
203+ fn main() {
204+ const fn fo$0o(s: String) -> String {
205+ s
206+ }
180207
181208 _ = foo("hello");
182209}
0 commit comments