Skip to content

Commit 42486b6

Browse files
committed
change as requested
1 parent f9c180f commit 42486b6

File tree

1 file changed

+86
-31
lines changed

1 file changed

+86
-31
lines changed

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

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,33 @@ use crate::{AssistContext, Assists};
3030
pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
3131
let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
3232

33-
is_option_or_result(call.receiver()?, ctx)?;
33+
let kind = is_option_or_result(call.receiver()?, ctx)?;
3434

3535
let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
3636

37+
let mut map_or = false;
38+
3739
let replace = match &*name.text() {
3840
"unwrap_or" => "unwrap_or_else".to_string(),
39-
"ok_or" => "ok_or_else".to_string(),
41+
"or" => "or_else".to_string(),
42+
"ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
43+
"map_or" => {
44+
map_or = true;
45+
"map_or_else".to_string()
46+
}
4047
_ => return None,
4148
};
4249

4350
let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
4451
[] => make::arg_list(Vec::new()),
4552
[first] => {
46-
let param = (|| {
47-
if let ast::Expr::CallExpr(call) = first {
48-
if call.arg_list()?.args().count() == 0 {
49-
Some(call.expr()?.clone())
50-
} else {
51-
None
52-
}
53-
} else {
54-
None
55-
}
56-
})()
57-
.unwrap_or_else(|| make::expr_closure(None, first.clone()));
53+
let param = into_closure(first);
5854
make::arg_list(vec![param])
5955
}
56+
[first, second] if map_or => {
57+
let param = into_closure(first);
58+
make::arg_list(vec![param, second.clone()])
59+
}
6060
_ => return None,
6161
};
6262

@@ -71,6 +71,21 @@ pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>
7171
)
7272
}
7373

74+
fn into_closure(param: &Expr) -> Expr {
75+
(|| {
76+
if let ast::Expr::CallExpr(call) = param {
77+
if call.arg_list()?.args().count() == 0 {
78+
Some(call.expr()?.clone())
79+
} else {
80+
None
81+
}
82+
} else {
83+
None
84+
}
85+
})()
86+
.unwrap_or_else(|| make::expr_closure(None, param.clone()))
87+
}
88+
7489
// Assist: replace_or_else_with_or
7590
//
7691
// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
@@ -92,33 +107,32 @@ pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>
92107
pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
93108
let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
94109

95-
is_option_or_result(call.receiver()?, ctx)?;
110+
let kind = is_option_or_result(call.receiver()?, ctx)?;
96111

97112
let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
98113

114+
let mut map_or = false;
99115
let replace = match &*name.text() {
100116
"unwrap_or_else" => "unwrap_or".to_string(),
101-
"ok_or_else" => "ok_or".to_string(),
117+
"or_else" => "or".to_string(),
118+
"ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
119+
"map_or_else" => {
120+
map_or = true;
121+
"map_or".to_string()
122+
}
102123
_ => return None,
103124
};
104125

105126
let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
106127
[] => make::arg_list(Vec::new()),
107128
[first] => {
108-
let param = (|| {
109-
if let ast::Expr::ClosureExpr(closure) = first {
110-
if closure.param_list()?.params().count() == 0 {
111-
Some(closure.body()?.clone())
112-
} else {
113-
None
114-
}
115-
} else {
116-
None
117-
}
118-
})()
119-
.unwrap_or_else(|| make::expr_call(first.clone(), make::arg_list(Vec::new())));
129+
let param = into_call(first);
120130
make::arg_list(vec![param])
121131
}
132+
[first, second] if map_or => {
133+
let param = into_call(first);
134+
make::arg_list(vec![param, second.clone()])
135+
}
122136
_ => return None,
123137
};
124138

@@ -133,14 +147,35 @@ pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>
133147
)
134148
}
135149

136-
fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<()> {
150+
fn into_call(param: &Expr) -> Expr {
151+
(|| {
152+
if let ast::Expr::ClosureExpr(closure) = param {
153+
if closure.param_list()?.params().count() == 0 {
154+
Some(closure.body()?.clone())
155+
} else {
156+
None
157+
}
158+
} else {
159+
None
160+
}
161+
})()
162+
.unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
163+
}
164+
165+
#[derive(PartialEq, Eq)]
166+
enum Kind {
167+
Option,
168+
Result,
169+
}
170+
171+
fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
137172
let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
138173
let option_enum =
139174
FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();
140175

141176
if let Some(option_enum) = option_enum {
142177
if ty == option_enum {
143-
return Some(());
178+
return Some(Kind::Option);
144179
}
145180
}
146181

@@ -149,7 +184,7 @@ fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<()> {
149184

150185
if let Some(result_enum) = result_enum {
151186
if ty == result_enum {
152-
return Some(());
187+
return Some(Kind::Result);
153188
}
154189
}
155190

@@ -294,6 +329,26 @@ fn foo() {
294329
)
295330
}
296331

332+
#[test]
333+
fn replace_or_else_with_or_map() {
334+
check_assist(
335+
replace_or_else_with_or,
336+
r#"
337+
//- minicore: result
338+
fn foo() {
339+
let foo = Ok("foo");
340+
return foo.map$0_or_else(|| 42, |v| v.len());
341+
}
342+
"#,
343+
r#"
344+
fn foo() {
345+
let foo = Ok("foo");
346+
return foo.map_or(42, |v| v.len());
347+
}
348+
"#,
349+
)
350+
}
351+
297352
#[test]
298353
fn replace_or_else_with_or_not_applicable() {
299354
check_assist_not_applicable(

0 commit comments

Comments
 (0)