Skip to content

Commit 641fa37

Browse files
bors[bot]dzvon
andauthored
Merge #10309
10309: use `ControlFlow` in "extract function" assist r=Veykril a=dzvon Fixes #10272 Co-authored-by: Dezhi Wu <[email protected]>
2 parents 7d1015b + 214e7cc commit 641fa37

File tree

2 files changed

+73
-16
lines changed

2 files changed

+73
-16
lines changed

crates/ide_assists/src/handlers/extract_function.rs

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ use std::{hash::BuildHasherDefault, iter};
22

33
use ast::make;
44
use either::Either;
5-
use hir::{HirDisplay, InFile, Local, Semantics, TypeInfo};
5+
use hir::{HirDisplay, InFile, Local, ModuleDef, Semantics, TypeInfo};
66
use ide_db::{
77
defs::{Definition, NameRefClass},
8-
helpers::node_ext::{preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr},
8+
helpers::{
9+
insert_use::{insert_use, ImportScope},
10+
mod_path_to_ast,
11+
node_ext::{preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr},
12+
FamousDefs,
13+
},
914
search::{FileReference, ReferenceCategory, SearchScope},
1015
RootDatabase,
1116
};
@@ -86,6 +91,8 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
8691

8792
let target_range = body.text_range();
8893

94+
let scope = ImportScope::find_insert_use_container_with_macros(&node, &ctx.sema)?;
95+
8996
acc.add(
9097
AssistId("extract_function", crate::AssistKind::RefactorExtract),
9198
"Extract into function",
@@ -118,10 +125,34 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
118125

119126
let fn_def = format_function(ctx, module, &fun, old_indent, new_indent);
120127
let insert_offset = insert_after.text_range().end();
128+
129+
if fn_def.contains("ControlFlow") {
130+
let scope = match scope {
131+
ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
132+
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
133+
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
134+
};
135+
136+
let control_flow_enum =
137+
FamousDefs(&ctx.sema, Some(module.krate())).core_ops_ControlFlow();
138+
139+
if let Some(control_flow_enum) = control_flow_enum {
140+
let mod_path = module.find_use_path_prefixed(
141+
ctx.sema.db,
142+
ModuleDef::from(control_flow_enum),
143+
ctx.config.insert_use.prefix_kind,
144+
);
145+
146+
if let Some(mod_path) = mod_path {
147+
insert_use(&scope, mod_path_to_ast(&mod_path), &ctx.config.insert_use);
148+
}
149+
}
150+
}
151+
121152
match ctx.config.snippet_cap {
122153
Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
123154
None => builder.insert(insert_offset, fn_def),
124-
}
155+
};
125156
},
126157
)
127158
}
@@ -1184,7 +1215,17 @@ impl FlowHandler {
11841215
let action = action.make_result_handler(None);
11851216
let stmt = make::expr_stmt(action);
11861217
let block = make::block_expr(iter::once(stmt.into()), None);
1187-
let condition = make::condition(call_expr, None);
1218+
let controlflow_break_path = make::path_from_text("ControlFlow::Break");
1219+
let condition = make::condition(
1220+
call_expr,
1221+
Some(
1222+
make::tuple_struct_pat(
1223+
controlflow_break_path,
1224+
iter::once(make::wildcard_pat().into()),
1225+
)
1226+
.into(),
1227+
),
1228+
);
11881229
make::expr_if(condition, block, None)
11891230
}
11901231
FlowHandler::IfOption { action } => {
@@ -1326,7 +1367,7 @@ impl Function {
13261367
.unwrap_or_else(make::ty_placeholder);
13271368
make::ext::ty_result(fun_ty.make_ty(ctx, module), handler_ty)
13281369
}
1329-
FlowHandler::If { .. } => make::ext::ty_bool(),
1370+
FlowHandler::If { .. } => make::ty("ControlFlow<()>"),
13301371
FlowHandler::IfOption { action } => {
13311372
let handler_ty = action
13321373
.expr_ty(ctx)
@@ -1461,8 +1502,11 @@ fn make_body(
14611502
})
14621503
}
14631504
FlowHandler::If { .. } => {
1464-
let lit_false = make::expr_literal("false");
1465-
with_tail_expr(block, lit_false.into())
1505+
let controlflow_continue = make::expr_call(
1506+
make::expr_path(make::path_from_text("ControlFlow::Continue")),
1507+
make::arg_list(iter::once(make::expr_unit())),
1508+
);
1509+
with_tail_expr(block, controlflow_continue.into())
14661510
}
14671511
FlowHandler::IfOption { .. } => {
14681512
let none = make::expr_path(make::ext::ident_path("None"));
@@ -1638,7 +1682,10 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) {
16381682
fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> {
16391683
let value = match handler {
16401684
FlowHandler::None | FlowHandler::Try { .. } => return None,
1641-
FlowHandler::If { .. } => make::expr_literal("true").into(),
1685+
FlowHandler::If { .. } => make::expr_call(
1686+
make::expr_path(make::path_from_text("ControlFlow::Break")),
1687+
make::arg_list(iter::once(make::expr_unit())),
1688+
),
16421689
FlowHandler::IfOption { .. } => {
16431690
let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
16441691
let args = make::arg_list(iter::once(expr));
@@ -3270,6 +3317,7 @@ fn foo() {
32703317
check_assist(
32713318
extract_function,
32723319
r#"
3320+
//- minicore: try
32733321
fn foo() {
32743322
loop {
32753323
let mut n = 1;
@@ -3281,21 +3329,23 @@ fn foo() {
32813329
}
32823330
"#,
32833331
r#"
3332+
use core::ops::ControlFlow;
3333+
32843334
fn foo() {
32853335
loop {
32863336
let mut n = 1;
3287-
if fun_name(&mut n) {
3337+
if let ControlFlow::Break(_) = fun_name(&mut n) {
32883338
break;
32893339
}
32903340
let h = 1 + n;
32913341
}
32923342
}
32933343
3294-
fn $0fun_name(n: &mut i32) -> bool {
3344+
fn $0fun_name(n: &mut i32) -> ControlFlow<()> {
32953345
let m = *n + 1;
3296-
return true;
3346+
return ControlFlow::Break(());
32973347
*n += m;
3298-
false
3348+
ControlFlow::Continue(())
32993349
}
33003350
"#,
33013351
);
@@ -3306,6 +3356,7 @@ fn $0fun_name(n: &mut i32) -> bool {
33063356
check_assist(
33073357
extract_function,
33083358
r#"
3359+
//- minicore: try
33093360
fn foo() {
33103361
loop {
33113362
let mut n = 1;
@@ -3318,22 +3369,24 @@ fn foo() {
33183369
}
33193370
"#,
33203371
r#"
3372+
use core::ops::ControlFlow;
3373+
33213374
fn foo() {
33223375
loop {
33233376
let mut n = 1;
3324-
if fun_name(n) {
3377+
if let ControlFlow::Break(_) = fun_name(n) {
33253378
break;
33263379
}
33273380
let h = 1;
33283381
}
33293382
}
33303383
3331-
fn $0fun_name(n: i32) -> bool {
3384+
fn $0fun_name(n: i32) -> ControlFlow<()> {
33323385
let m = n + 1;
33333386
if m == 42 {
3334-
return true;
3387+
return ControlFlow::Break(());
33353388
}
3336-
false
3389+
ControlFlow::Continue(())
33373390
}
33383391
"#,
33393392
);

crates/ide_db/src/helpers/famous_defs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ impl FamousDefs<'_, '_> {
6868
self.find_trait("core:ops:Deref")
6969
}
7070

71+
pub fn core_ops_ControlFlow(&self) -> Option<Enum> {
72+
self.find_enum("core:ops:ControlFlow")
73+
}
74+
7175
pub fn alloc(&self) -> Option<Crate> {
7276
self.find_crate("alloc")
7377
}

0 commit comments

Comments
 (0)