2 assists::{AssistId, AssistKind},
3 famous_defs::FamousDefs,
6 ast::{self, make, Expr, HasArgList},
10 use crate::{AssistContext, Assists};
12 // Assist: replace_or_with_or_else
14 // Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
17 // # //- minicore:option
27 // a.unwrap_or_else(|| 2);
30 pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
31 let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
33 let kind = is_option_or_result(call.receiver()?, ctx)?;
35 let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
37 let mut map_or = false;
39 let replace = match &*name.text() {
40 "unwrap_or" => "unwrap_or_else".to_string(),
41 "or" => "or_else".to_string(),
42 "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
45 "map_or_else".to_string()
50 let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
51 [] => make::arg_list(Vec::new()),
53 let param = into_closure(first);
54 make::arg_list(vec![param])
56 [first, second] if map_or => {
57 let param = into_closure(first);
58 make::arg_list(vec![param, second.clone()])
64 AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
65 format!("Replace {} with {}", name.text(), replace),
66 call.syntax().text_range(),
68 builder.replace(name.syntax().text_range(), replace);
69 builder.replace_ast(arg_list, arg)
74 fn into_closure(param: &Expr) -> Expr {
76 if let ast::Expr::CallExpr(call) = param {
77 if call.arg_list()?.args().count() == 0 {
78 Some(call.expr()?.clone())
86 .unwrap_or_else(|| make::expr_closure(None, param.clone()))
89 // Assist: replace_or_else_with_or
91 // Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
94 // # //- minicore:option
97 // a.unwra$0p_or_else(|| 2);
107 pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
108 let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
110 let kind = is_option_or_result(call.receiver()?, ctx)?;
112 let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
114 let mut map_or = false;
115 let replace = match &*name.text() {
116 "unwrap_or_else" => "unwrap_or".to_string(),
117 "or_else" => "or".to_string(),
118 "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
126 let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
127 [] => make::arg_list(Vec::new()),
129 let param = into_call(first);
130 make::arg_list(vec![param])
132 [first, second] if map_or => {
133 let param = into_call(first);
134 make::arg_list(vec![param, second.clone()])
140 AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
141 format!("Replace {} with {}", name.text(), replace),
142 call.syntax().text_range(),
144 builder.replace(name.syntax().text_range(), replace);
145 builder.replace_ast(arg_list, arg)
150 fn into_call(param: &Expr) -> Expr {
152 if let ast::Expr::ClosureExpr(closure) = param {
153 if closure.param_list()?.params().count() == 0 {
154 Some(closure.body()?.clone())
162 .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
165 #[derive(PartialEq, Eq)]
171 fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
172 let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
174 FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();
176 if let Some(option_enum) = option_enum {
177 if ty == option_enum {
178 return Some(Kind::Option);
183 FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();
185 if let Some(result_enum) = result_enum {
186 if ty == result_enum {
187 return Some(Kind::Result);
196 use crate::tests::{check_assist, check_assist_not_applicable};
201 fn replace_or_with_or_else_simple() {
203 replace_or_with_or_else,
208 return foo.unwrap_$0or(2);
214 return foo.unwrap_or_else(|| 2);
221 fn replace_or_with_or_else_call() {
223 replace_or_with_or_else,
228 return foo.unwrap_$0or(x());
234 return foo.unwrap_or_else(x);
241 fn replace_or_with_or_else_block() {
243 replace_or_with_or_else,
248 return foo.unwrap_$0or({
260 return foo.unwrap_or_else(|| {
273 fn replace_or_else_with_or_simple() {
275 replace_or_else_with_or,
280 return foo.unwrap_$0or_else(|| 2);
286 return foo.unwrap_or(2);
293 fn replace_or_else_with_or_call() {
295 replace_or_else_with_or,
300 return foo.unwrap_$0or_else(x);
306 return foo.unwrap_or(x());
313 fn replace_or_else_with_or_result() {
315 replace_or_else_with_or,
320 return foo.unwrap_$0or_else(x);
326 return foo.unwrap_or(x());
333 fn replace_or_else_with_or_map() {
335 replace_or_else_with_or,
340 return foo.map$0_or_else(|| 42, |v| v.len());
346 return foo.map_or(42, |v| v.len());
353 fn replace_or_else_with_or_not_applicable() {
354 check_assist_not_applicable(
355 replace_or_else_with_or,
359 return foo.unwrap_$0or_else(x);