Skip to content

Commit 477388d

Browse files
committed
Add ExprStmt and Expr for convert_attr_cfg_to_if
1 parent abe79f1 commit 477388d

File tree

1 file changed

+208
-8
lines changed

1 file changed

+208
-8
lines changed

crates/ide-assists/src/handlers/convert_attr_cfg_to_if.rs

Lines changed: 208 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use either::Either::{self, Left, Right};
12
use ide_db::assists::AssistId;
23
use syntax::ast::edit_in_place::Indent;
34
use syntax::syntax_editor::SyntaxEditor;
@@ -29,8 +30,7 @@ use crate::assist_context::{AssistContext, Assists};
2930
// }
3031
// ```
3132
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)?;
3434

3535
if cfg.path()?.as_single_name_ref()?.text() != "cfg" {
3636
return None;
@@ -43,20 +43,68 @@ pub(crate) fn convert_attr_cfg_to_if(acc: &mut Assists, ctx: &AssistContext<'_>)
4343
"Convert `#[cfg()]` to `if cfg!()`",
4444
cfg.syntax().text_range(),
4545
|builder| {
46-
let mut edit = builder.make_editor(stmt_list.syntax());
46+
let mut edit = builder.make_editor(origin.syntax());
4747

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+
};
5155
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());
5458

5559
builder.add_file_edits(ctx.vfs_file_id(), edit);
5660
},
5761
)
5862
}
5963

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+
60108
fn find_stmt_list(attr: &ast::Attr) -> Option<ast::StmtList> {
61109
let mut node = attr.syntax().clone();
62110

@@ -106,6 +154,28 @@ fn foo() {
106154
);
107155
}
108156

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+
109179
#[test]
110180
fn test_other_attr() {
111181
check_assist(
@@ -127,6 +197,136 @@ fn foo() {
127197
let x = 2;
128198
let _ = x+1;
129199
}
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+
}
130330
}
131331
"#,
132332
);

0 commit comments

Comments
 (0)