Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit dbaf2ce

Browse files
committed
turn unwrap_or into unwrap_or_else and vice versa
1 parent e8e598f commit dbaf2ce

File tree

2 files changed

+233
-0
lines changed

2 files changed

+233
-0
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
use ide_db::assists::{AssistId, AssistKind};
2+
use syntax::{
3+
ast::{self, make, HasArgList},
4+
AstNode,
5+
};
6+
7+
use crate::{AssistContext, Assists};
8+
9+
// Assist: replace_or_with_or_else
10+
//
11+
// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
12+
//
13+
// ```
14+
// let a = Some(1);
15+
// a.unwra$0p_or(2);
16+
// ```
17+
// ->
18+
// ```
19+
// let a = Some(1);
20+
// a.unwrap_or_else(|| 2);
21+
// ```
22+
pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
23+
let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
24+
let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
25+
26+
let replace = match &*name.text() {
27+
"unwrap_or" => "unwrap_or_else".to_string(),
28+
"ok_or" => "ok_or_else".to_string(),
29+
_ => return None,
30+
};
31+
32+
let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
33+
[] => make::arg_list(Vec::new()),
34+
[first] => {
35+
let param = (|| {
36+
if let ast::Expr::CallExpr(call) = first {
37+
if call.arg_list()?.args().count() == 0 {
38+
Some(call.expr()?.clone())
39+
} else {
40+
None
41+
}
42+
} else {
43+
None
44+
}
45+
})()
46+
.unwrap_or_else(|| make::expr_closure(None, first.clone()));
47+
make::arg_list(vec![param])
48+
}
49+
_ => return None,
50+
};
51+
52+
acc.add(
53+
AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
54+
"Replace unwrap_or or ok_or with lazy version",
55+
call.syntax().text_range(),
56+
|builder| {
57+
builder.replace(name.syntax().text_range(), replace);
58+
builder.replace_ast(arg_list, arg)
59+
},
60+
)
61+
}
62+
63+
// Assist: replace_or_else_with_or
64+
//
65+
// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
66+
//
67+
// ```
68+
// let a = Some(1);
69+
// a.unwra$0p_or_else(|| 2);
70+
// ```
71+
// ->
72+
// ```
73+
// let a = Some(1);
74+
// a.unwrap_or(2);
75+
// ```
76+
pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
77+
let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
78+
79+
let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
80+
81+
let replace = match &*name.text() {
82+
"unwrap_or_else" => "unwrap_or".to_string(),
83+
"ok_or_else" => "ok_or".to_string(),
84+
_ => return None,
85+
};
86+
87+
let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
88+
[] => make::arg_list(Vec::new()),
89+
[first] => {
90+
let param = (|| {
91+
if let ast::Expr::ClosureExpr(closure) = first {
92+
if closure.param_list()?.params().count() == 0 {
93+
Some(closure.body()?.clone())
94+
} else {
95+
None
96+
}
97+
} else {
98+
None
99+
}
100+
})()
101+
.unwrap_or_else(|| make::expr_call(first.clone(), make::arg_list(Vec::new())));
102+
make::arg_list(vec![param])
103+
}
104+
_ => return None,
105+
};
106+
107+
acc.add(
108+
AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
109+
"Replace unwrap_or_else or ok_or_else with eager version",
110+
call.syntax().text_range(),
111+
|builder| {
112+
builder.replace(name.syntax().text_range(), replace);
113+
builder.replace_ast(arg_list, arg)
114+
},
115+
)
116+
}
117+
118+
#[cfg(test)]
119+
mod tests {
120+
use crate::tests::check_assist;
121+
122+
use super::*;
123+
124+
#[test]
125+
fn replace_or_with_or_else_simple() {
126+
check_assist(
127+
replace_or_with_or_else,
128+
r#"
129+
fn foo() {
130+
let foo = Some(1);
131+
return foo.unwrap_$0or(2);
132+
}
133+
"#,
134+
r#"
135+
fn foo() {
136+
let foo = Some(1);
137+
return foo.unwrap_or_else(|| 2);
138+
}
139+
"#,
140+
)
141+
}
142+
143+
#[test]
144+
fn replace_or_with_or_else_call() {
145+
check_assist(
146+
replace_or_with_or_else,
147+
r#"
148+
fn foo() {
149+
let foo = Some(1);
150+
return foo.unwrap_$0or(x());
151+
}
152+
"#,
153+
r#"
154+
fn foo() {
155+
let foo = Some(1);
156+
return foo.unwrap_or_else(x);
157+
}
158+
"#,
159+
)
160+
}
161+
162+
#[test]
163+
fn replace_or_with_or_else_block() {
164+
check_assist(
165+
replace_or_with_or_else,
166+
r#"
167+
fn foo() {
168+
let foo = Some(1);
169+
return foo.unwrap_$0or({
170+
let mut x = bar();
171+
for i in 0..10 {
172+
x += i;
173+
}
174+
x
175+
});
176+
}
177+
"#,
178+
r#"
179+
fn foo() {
180+
let foo = Some(1);
181+
return foo.unwrap_or_else(|| {
182+
let mut x = bar();
183+
for i in 0..10 {
184+
x += i;
185+
}
186+
x
187+
});
188+
}
189+
"#,
190+
)
191+
}
192+
193+
#[test]
194+
fn replace_or_else_with_or_simple() {
195+
check_assist(
196+
replace_or_else_with_or,
197+
r#"
198+
fn foo() {
199+
let foo = Some(1);
200+
return foo.unwrap_$0or_else(|| 2);
201+
}
202+
"#,
203+
r#"
204+
fn foo() {
205+
let foo = Some(1);
206+
return foo.unwrap_or(2);
207+
}
208+
"#,
209+
)
210+
}
211+
212+
#[test]
213+
fn replace_or_else_with_or_call() {
214+
check_assist(
215+
replace_or_else_with_or,
216+
r#"
217+
fn foo() {
218+
let foo = Some(1);
219+
return foo.unwrap_$0or_else(x);
220+
}
221+
"#,
222+
r#"
223+
fn foo() {
224+
let foo = Some(1);
225+
return foo.unwrap_or(x());
226+
}
227+
"#,
228+
)
229+
}
230+
}

crates/ide-assists/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ mod handlers {
179179
mod replace_try_expr_with_match;
180180
mod replace_derive_with_manual_impl;
181181
mod replace_if_let_with_match;
182+
mod replace_or_with_or_else;
182183
mod introduce_named_generic;
183184
mod replace_let_with_if_let;
184185
mod replace_qualified_name_with_use;
@@ -273,6 +274,8 @@ mod handlers {
273274
replace_if_let_with_match::replace_if_let_with_match,
274275
replace_if_let_with_match::replace_match_with_if_let,
275276
replace_let_with_if_let::replace_let_with_if_let,
277+
replace_or_with_or_else::replace_or_else_with_or,
278+
replace_or_with_or_else::replace_or_with_or_else,
276279
replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
277280
replace_qualified_name_with_use::replace_qualified_name_with_use,
278281
sort_items::sort_items,

0 commit comments

Comments
 (0)