Skip to content

Commit ac300ea

Browse files
bors[bot]Veykril
andauthored
Merge #9497
9497: Wrap inlined closures in parens when inlined in an expression in `inline_call` r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2 parents 1ef077a + dafbe69 commit ac300ea

File tree

6 files changed

+101
-40
lines changed

6 files changed

+101
-40
lines changed

crates/ide_assists/src/handlers/inline_call.rs

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,23 @@ use crate::{
1414

1515
// Assist: inline_call
1616
//
17-
// Inlines a function or method body.
17+
// Inlines a function or method body creating a `let` statement per parameter unless the parameter
18+
// can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
19+
// or if the parameter is only accessed inside the function body once.
1820
//
1921
// ```
20-
// fn align(a: u32, b: u32) -> u32 {
21-
// (a + b - 1) & !(b - 1)
22-
// }
23-
// fn main() {
24-
// let x = align$0(1, 2);
22+
// # //- minicore: option
23+
// fn foo(name: Option<&str>) {
24+
// let name = name.unwrap$0();
2525
// }
2626
// ```
2727
// ->
2828
// ```
29-
// fn align(a: u32, b: u32) -> u32 {
30-
// (a + b - 1) & !(b - 1)
31-
// }
32-
// fn main() {
33-
// let x = {
34-
// let b = 2;
35-
// (1 + b - 1) & !(b - 1)
36-
// };
29+
// fn foo(name: Option<&str>) {
30+
// let name = match name {
31+
// Some(val) => val,
32+
// None => panic!("called `Option::unwrap()` on a `None` value"),
33+
// };
3734
// }
3835
// ```
3936
pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -137,7 +134,7 @@ pub(crate) fn inline_(
137134
.covering_element(range)
138135
.ancestors()
139136
.nth(3)
140-
.filter(|it| ast::PathExpr::can_cast(it.kind())),
137+
.and_then(ast::PathExpr::cast),
141138
_ => None,
142139
})
143140
.collect::<Option<Vec<_>>>()
@@ -163,7 +160,14 @@ pub(crate) fn inline_(
163160
match &*usages {
164161
// inline single use parameters
165162
[usage] => {
166-
ted::replace(usage, expr.syntax().clone_for_update());
163+
let expr = if matches!(expr, ast::Expr::ClosureExpr(_))
164+
&& usage.syntax().parent().and_then(ast::Expr::cast).is_some()
165+
{
166+
make::expr_paren(expr)
167+
} else {
168+
expr
169+
};
170+
ted::replace(usage.syntax(), expr.syntax().clone_for_update());
167171
}
168172
// inline parameters whose expression is a simple local reference
169173
[_, ..]
@@ -173,7 +177,7 @@ pub(crate) fn inline_(
173177
) =>
174178
{
175179
usages.into_iter().for_each(|usage| {
176-
ted::replace(usage, &expr.syntax().clone_for_update());
180+
ted::replace(usage.syntax(), &expr.syntax().clone_for_update());
177181
});
178182
}
179183
// cant inline, emit a let statement
@@ -540,6 +544,56 @@ impl Foo {
540544
};
541545
}
542546
}
547+
"#,
548+
);
549+
}
550+
551+
#[test]
552+
fn wraps_closure_in_paren() {
553+
check_assist(
554+
inline_call,
555+
r#"
556+
fn foo(x: fn()) {
557+
x();
558+
}
559+
560+
fn main() {
561+
foo$0(|| {})
562+
}
563+
"#,
564+
r#"
565+
fn foo(x: fn()) {
566+
x();
567+
}
568+
569+
fn main() {
570+
{
571+
(|| {})();
572+
}
573+
}
574+
"#,
575+
);
576+
check_assist(
577+
inline_call,
578+
r#"
579+
fn foo(x: fn()) {
580+
x();
581+
}
582+
583+
fn main() {
584+
foo$0(main)
585+
}
586+
"#,
587+
r#"
588+
fn foo(x: fn()) {
589+
x();
590+
}
591+
592+
fn main() {
593+
{
594+
main();
595+
}
596+
}
543597
"#,
544598
);
545599
}

crates/ide_assists/src/tests/generated.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -923,22 +923,17 @@ fn doctest_inline_call() {
923923
check_doc_test(
924924
"inline_call",
925925
r#####"
926-
fn align(a: u32, b: u32) -> u32 {
927-
(a + b - 1) & !(b - 1)
928-
}
929-
fn main() {
930-
let x = align$0(1, 2);
926+
//- minicore: option
927+
fn foo(name: Option<&str>) {
928+
let name = name.unwrap$0();
931929
}
932930
"#####,
933931
r#####"
934-
fn align(a: u32, b: u32) -> u32 {
935-
(a + b - 1) & !(b - 1)
936-
}
937-
fn main() {
938-
let x = {
939-
let b = 2;
940-
(1 + b - 1) & !(b - 1)
941-
};
932+
fn foo(name: Option<&str>) {
933+
let name = match name {
934+
Some(val) => val,
935+
None => panic!("called `Option::unwrap()` on a `None` value"),
936+
};
942937
}
943938
"#####,
944939
)

crates/ide_db/src/helpers/insert_use.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
//! Handle syntactic aspects of inserting a new `use`.
2+
#[cfg(test)]
3+
mod tests;
4+
25
use std::cmp::Ordering;
36

47
use hir::Semantics;
@@ -378,5 +381,3 @@ fn is_inner_comment(token: SyntaxToken) -> bool {
378381
ast::Comment::cast(token).and_then(|comment| comment.kind().doc)
379382
== Some(ast::CommentPlacement::Inner)
380383
}
381-
#[cfg(test)]
382-
mod tests;

crates/ide_db/src/helpers/insert_use/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn foo() {$0}
1414
r#"
1515
#[cfg(test)]
1616
fn foo() {
17-
use bar::Bar;
17+
use bar::Bar;
1818
}
1919
"#,
2020
ImportGranularity::Crate,
@@ -32,7 +32,7 @@ const FOO: Bar = {$0};
3232
r#"
3333
#[cfg(test)]
3434
const FOO: Bar = {
35-
use bar::Bar;
35+
use bar::Bar;
3636
};
3737
"#,
3838
ImportGranularity::Crate,

crates/syntax/src/ted.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,14 @@ fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
161161
}
162162
}
163163

164+
if prev.kind() == T!['{'] && ast::Stmt::can_cast(new.kind()) {
165+
if let Some(block_expr) = prev.parent().and_then(ast::BlockExpr::cast) {
166+
let mut indent = IndentLevel::from_element(&block_expr.syntax().clone().into());
167+
indent.0 += 1;
168+
return Some(make::tokens::whitespace(&format!("\n{}", indent)));
169+
}
170+
}
171+
164172
ws_between(prev, new)
165173
}
166174
fn ws_after(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
@@ -187,12 +195,6 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken
187195
return None;
188196
}
189197

190-
if left.kind() == T!['{'] && right.kind() == SyntaxKind::LET_STMT {
191-
let mut indent = IndentLevel::from_element(left);
192-
indent.0 += 1;
193-
return Some(make::tokens::whitespace(&format!("\n{}", indent)));
194-
}
195-
196198
if right.kind() == SyntaxKind::USE {
197199
let mut indent = IndentLevel::from_element(left);
198200
if left.kind() == SyntaxKind::USE {

crates/test_utils/src/minicore.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ pub mod option {
330330
#[lang = "Some"]
331331
Some(T),
332332
}
333+
334+
impl<T> Option<T> {
335+
pub const fn unwrap(self) -> T {
336+
match self {
337+
Some(val) => val,
338+
None => panic!("called `Option::unwrap()` on a `None` value"),
339+
}
340+
}
341+
}
333342
}
334343
// endregion:option
335344

0 commit comments

Comments
 (0)