1
+ use either:: Either :: { self , Left , Right } ;
1
2
use ide_db:: assists:: AssistId ;
2
3
use syntax:: ast:: edit_in_place:: Indent ;
3
4
use syntax:: syntax_editor:: SyntaxEditor ;
@@ -29,8 +30,7 @@ use crate::assist_context::{AssistContext, Assists};
29
30
// }
30
31
// ```
31
32
pub ( crate ) fn convert_attr_cfg_to_if ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
32
- let cfg = ctx. find_node_at_offset :: < ast:: Attr > ( ) ?;
33
- let stmt_list = find_stmt_list ( & cfg) ?;
33
+ let ( origin, cfg, stmt) = find_stmt ( ctx) ?;
34
34
35
35
if cfg. path ( ) ?. as_single_name_ref ( ) ?. text ( ) != "cfg" {
36
36
return None ;
@@ -43,20 +43,68 @@ pub(crate) fn convert_attr_cfg_to_if(acc: &mut Assists, ctx: &AssistContext<'_>)
43
43
"Convert `#[cfg()]` to `if cfg!()`" ,
44
44
cfg. syntax ( ) . text_range ( ) ,
45
45
|builder| {
46
- let mut edit = builder. make_editor ( stmt_list . syntax ( ) ) ;
46
+ let mut edit = builder. make_editor ( origin . syntax ( ) ) ;
47
47
48
- remove_cfg ( & cfg, & mut edit) ;
49
-
50
- let block = make:: block_expr ( stmt_list. statements ( ) , None ) ;
48
+ let block = match stmt {
49
+ Left ( stmt_list) => {
50
+ remove_cfg ( & cfg, & mut edit) ;
51
+ make_block ( stmt_list. statements ( ) , stmt_list. tail_expr ( ) )
52
+ }
53
+ Right ( stmt) => make_block ( [ stmt] , None ) ,
54
+ } ;
51
55
let if_expr = make:: expr_if ( cfg_expr, block, None ) . clone_for_update ( ) ;
52
- if_expr. indent ( stmt_list . indent_level ( ) ) ;
53
- edit. replace ( stmt_list . syntax ( ) , if_expr. syntax ( ) ) ;
56
+ if_expr. indent ( origin . indent_level ( ) ) ;
57
+ edit. replace ( origin . syntax ( ) , if_expr. syntax ( ) ) ;
54
58
55
59
builder. add_file_edits ( ctx. vfs_file_id ( ) , edit) ;
56
60
} ,
57
61
)
58
62
}
59
63
64
+ fn make_block (
65
+ stmts : impl IntoIterator < Item = ast:: Stmt > ,
66
+ tail_expr : Option < ast:: Expr > ,
67
+ ) -> ast:: BlockExpr {
68
+ let tail_expr = tail_expr. inspect ( |expr| expr. reindent_to ( 1 . into ( ) ) ) ;
69
+ let stmts = stmts. into_iter ( ) . inspect ( |stmt| stmt. reindent_to ( 1 . into ( ) ) ) ;
70
+
71
+ make:: block_expr ( stmts, tail_expr)
72
+ }
73
+
74
+ fn find_stmt (
75
+ ctx : & AssistContext < ' _ > ,
76
+ ) -> Option < ( impl Indent , ast:: Attr , Either < ast:: StmtList , ast:: Stmt > ) > {
77
+ let attr = ctx. find_node_at_offset :: < ast:: Attr > ( ) ?;
78
+
79
+ if let Some ( stmt_list) = find_stmt_list ( & attr) {
80
+ let new_stmt_list = stmt_list. clone_for_update ( ) ;
81
+ new_stmt_list. dedent ( stmt_list. indent_level ( ) ) ;
82
+ return Some ( ( Left ( stmt_list) , attr, Left ( new_stmt_list) ) ) ;
83
+ }
84
+
85
+ let node =
86
+ match attr. syntax ( ) . ancestors ( ) . find_map ( Either :: < ast:: ExprStmt , ast:: StmtList > :: cast) ? {
87
+ Left ( expr_stmt) => Left ( expr_stmt) ,
88
+ Right ( list) => Right ( list. tail_expr ( ) ?) ,
89
+ } ;
90
+
91
+ let new_node = node. syntax ( ) . clone_subtree ( ) ;
92
+ let attr = new_node
93
+ . descendants ( )
94
+ . filter ( |node| node. text ( ) == attr. syntax ( ) . text ( ) )
95
+ . find_map ( ast:: Attr :: cast) ?;
96
+
97
+ let mut edit = SyntaxEditor :: new ( new_node) ;
98
+ remove_cfg ( & attr, & mut edit) ;
99
+ let new_node = edit. finish ( ) . new_root ( ) . clone ( ) ;
100
+ let new_stmt = match Either :: < ast:: ExprStmt , ast:: Expr > :: cast ( new_node) ? {
101
+ Left ( expr_stmt) => ast:: Stmt :: from ( expr_stmt) ,
102
+ Right ( expr) => make:: expr_stmt ( expr) . clone_for_update ( ) . into ( ) ,
103
+ } ;
104
+ new_stmt. dedent ( node. indent_level ( ) ) ;
105
+ Some ( ( Right ( node) , attr, Right ( new_stmt) ) )
106
+ }
107
+
60
108
fn find_stmt_list ( attr : & ast:: Attr ) -> Option < ast:: StmtList > {
61
109
let mut node = attr. syntax ( ) . clone ( ) ;
62
110
@@ -106,6 +154,28 @@ fn foo() {
106
154
) ;
107
155
}
108
156
157
+ #[ test]
158
+ fn test_expr_stmt ( ) {
159
+ check_assist (
160
+ convert_attr_cfg_to_if,
161
+ r#"
162
+ fn bar() {}
163
+ fn foo() {
164
+ $0#[cfg(feature = "foo")]
165
+ bar();
166
+ }
167
+ "# ,
168
+ r#"
169
+ fn bar() {}
170
+ fn foo() {
171
+ if cfg!(feature = "foo") {
172
+ bar();
173
+ }
174
+ }
175
+ "# ,
176
+ ) ;
177
+ }
178
+
109
179
#[ test]
110
180
fn test_other_attr ( ) {
111
181
check_assist (
@@ -127,6 +197,136 @@ fn foo() {
127
197
let x = 2;
128
198
let _ = x+1;
129
199
}
200
+ }
201
+ "# ,
202
+ ) ;
203
+
204
+ check_assist (
205
+ convert_attr_cfg_to_if,
206
+ r#"
207
+ fn bar() {}
208
+ fn foo() {
209
+ #[allow(unused)]
210
+ $0#[cfg(feature = "foo")]
211
+ bar();
212
+ }
213
+ "# ,
214
+ r#"
215
+ fn bar() {}
216
+ fn foo() {
217
+ if cfg!(feature = "foo") {
218
+ #[allow(unused)]
219
+ bar();
220
+ }
221
+ }
222
+ "# ,
223
+ ) ;
224
+ }
225
+
226
+ #[ test]
227
+ fn test_stmt_list_indent ( ) {
228
+ check_assist (
229
+ convert_attr_cfg_to_if,
230
+ r#"
231
+ mod a {
232
+ fn foo() {
233
+ #[allow(unused)]
234
+ $0#[cfg(feature = "foo")]
235
+ {
236
+ let _ = match () {
237
+ () => {
238
+ todo!()
239
+ },
240
+ };
241
+ match () {
242
+ () => {
243
+ todo!()
244
+ },
245
+ }
246
+ }
247
+ }
248
+ }
249
+ "# ,
250
+ r#"
251
+ mod a {
252
+ fn foo() {
253
+ #[allow(unused)]
254
+ if cfg!(feature = "foo") {
255
+ let _ = match () {
256
+ () => {
257
+ todo!()
258
+ },
259
+ };
260
+ match () {
261
+ () => {
262
+ todo!()
263
+ },
264
+ }
265
+ }
266
+ }
267
+ }
268
+ "# ,
269
+ ) ;
270
+ }
271
+
272
+ #[ test]
273
+ fn test_expr_indent ( ) {
274
+ check_assist (
275
+ convert_attr_cfg_to_if,
276
+ r#"
277
+ mod a {
278
+ fn foo() {
279
+ #[allow(unused)]
280
+ $0#[cfg(feature = "foo")]
281
+ match () {
282
+ () => {
283
+ todo!()
284
+ },
285
+ }
286
+ }
287
+ }
288
+ "# ,
289
+ r#"
290
+ mod a {
291
+ fn foo() {
292
+ if cfg!(feature = "foo") {
293
+ #[allow(unused)]
294
+ match () {
295
+ () => {
296
+ todo!()
297
+ },
298
+ }
299
+ }
300
+ }
301
+ }
302
+ "# ,
303
+ ) ;
304
+
305
+ check_assist (
306
+ convert_attr_cfg_to_if,
307
+ r#"
308
+ mod a {
309
+ fn foo() {
310
+ $0#[cfg(feature = "foo")]
311
+ match () {
312
+ () => {
313
+ todo!()
314
+ },
315
+ };
316
+ }
317
+ }
318
+ "# ,
319
+ r#"
320
+ mod a {
321
+ fn foo() {
322
+ if cfg!(feature = "foo") {
323
+ match () {
324
+ () => {
325
+ todo!()
326
+ },
327
+ };
328
+ }
329
+ }
130
330
}
131
331
"# ,
132
332
) ;
0 commit comments