From 2579dc6d82dff5d2b86f490121fe8b087216b74e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 5 Jul 2021 14:24:25 +0200 Subject: [PATCH 1/2] Update `inline_call` assist doc example --- .../ide_assists/src/handlers/inline_call.rs | 21 +++++++------------ crates/ide_assists/src/tests/generated.rs | 21 +++++++------------ crates/syntax/src/ted.rs | 14 +++++++------ crates/test_utils/src/minicore.rs | 9 ++++++++ 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs index 5b6992b6409..2059a7472d7 100644 --- a/crates/ide_assists/src/handlers/inline_call.rs +++ b/crates/ide_assists/src/handlers/inline_call.rs @@ -17,23 +17,18 @@ // Inlines a function or method body. // // ``` -// fn align(a: u32, b: u32) -> u32 { -// (a + b - 1) & !(b - 1) -// } -// fn main() { -// let x = align$0(1, 2); +// # //- minicore: option +// fn foo(name: Option<&str>) { +// let name = name.unwrap$0(); // } // ``` // -> // ``` -// fn align(a: u32, b: u32) -> u32 { -// (a + b - 1) & !(b - 1) -// } -// fn main() { -// let x = { -// let b = 2; -// (1 + b - 1) & !(b - 1) -// }; +// fn foo(name: Option<&str>) { +// let name = match name { +// Some(val) => val, +// None => panic!("called `Option::unwrap()` on a `None` value"), +// }; // } // ``` pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index c24c3803450..e35e68b40dc 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs @@ -923,22 +923,17 @@ fn doctest_inline_call() { check_doc_test( "inline_call", r#####" -fn align(a: u32, b: u32) -> u32 { - (a + b - 1) & !(b - 1) -} -fn main() { - let x = align$0(1, 2); +//- minicore: option +fn foo(name: Option<&str>) { + let name = name.unwrap$0(); } "#####, r#####" -fn align(a: u32, b: u32) -> u32 { - (a + b - 1) & !(b - 1) -} -fn main() { - let x = { - let b = 2; - (1 + b - 1) & !(b - 1) - }; +fn foo(name: Option<&str>) { + let name = match name { + Some(val) => val, + None => panic!("called `Option::unwrap()` on a `None` value"), + }; } "#####, ) diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index 3c05b488157..2396408270e 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs @@ -161,6 +161,14 @@ fn ws_before(position: &Position, new: &SyntaxElement) -> Option { } } + if prev.kind() == T!['{'] && ast::Stmt::can_cast(new.kind()) { + if let Some(block_expr) = prev.parent().and_then(ast::BlockExpr::cast) { + let mut indent = IndentLevel::from_element(&block_expr.syntax().clone().into()); + indent.0 += 1; + return Some(make::tokens::whitespace(&format!("\n{}", indent))); + } + } + ws_between(prev, new) } fn ws_after(position: &Position, new: &SyntaxElement) -> Option { @@ -187,12 +195,6 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option { #[lang = "Some"] Some(T), } + + impl Option { + pub const fn unwrap(self) -> T { + match self { + Some(val) => val, + None => panic!("called `Option::unwrap()` on a `None` value"), + } + } + } } // endregion:option From dafbe6940e6cbcd4a98e31c5e851c314e3640888 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 5 Jul 2021 15:34:01 +0200 Subject: [PATCH 2/2] Wrap inlined closures in parens when inlined in an expression in `inline_call` --- .../ide_assists/src/handlers/inline_call.rs | 67 +++++++++++++++++-- crates/ide_db/src/helpers/insert_use.rs | 5 +- crates/ide_db/src/helpers/insert_use/tests.rs | 4 +- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs index 2059a7472d7..f6840a27b30 100644 --- a/crates/ide_assists/src/handlers/inline_call.rs +++ b/crates/ide_assists/src/handlers/inline_call.rs @@ -14,7 +14,9 @@ // Assist: inline_call // -// Inlines a function or method body. +// Inlines a function or method body creating a `let` statement per parameter unless the parameter +// can be inlined. The parameter will be inlined either if it the supplied argument is a simple local +// or if the parameter is only accessed inside the function body once. // // ``` // # //- minicore: option @@ -132,7 +134,7 @@ pub(crate) fn inline_( .covering_element(range) .ancestors() .nth(3) - .filter(|it| ast::PathExpr::can_cast(it.kind())), + .and_then(ast::PathExpr::cast), _ => None, }) .collect::>>() @@ -158,7 +160,14 @@ pub(crate) fn inline_( match &*usages { // inline single use parameters [usage] => { - ted::replace(usage, expr.syntax().clone_for_update()); + let expr = if matches!(expr, ast::Expr::ClosureExpr(_)) + && usage.syntax().parent().and_then(ast::Expr::cast).is_some() + { + make::expr_paren(expr) + } else { + expr + }; + ted::replace(usage.syntax(), expr.syntax().clone_for_update()); } // inline parameters whose expression is a simple local reference [_, ..] @@ -168,7 +177,7 @@ pub(crate) fn inline_( ) => { usages.into_iter().for_each(|usage| { - ted::replace(usage, &expr.syntax().clone_for_update()); + ted::replace(usage.syntax(), &expr.syntax().clone_for_update()); }); } // cant inline, emit a let statement @@ -535,6 +544,56 @@ fn bar(&self) { }; } } +"#, + ); + } + + #[test] + fn wraps_closure_in_paren() { + check_assist( + inline_call, + r#" +fn foo(x: fn()) { + x(); +} + +fn main() { + foo$0(|| {}) +} +"#, + r#" +fn foo(x: fn()) { + x(); +} + +fn main() { + { + (|| {})(); + } +} +"#, + ); + check_assist( + inline_call, + r#" +fn foo(x: fn()) { + x(); +} + +fn main() { + foo$0(main) +} +"#, + r#" +fn foo(x: fn()) { + x(); +} + +fn main() { + { + main(); + } +} "#, ); } diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 4e12fe15079..e16021c82ff 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs @@ -1,4 +1,7 @@ //! Handle syntactic aspects of inserting a new `use`. +#[cfg(test)] +mod tests; + use std::cmp::Ordering; use hir::Semantics; @@ -378,5 +381,3 @@ fn is_inner_comment(token: SyntaxToken) -> bool { ast::Comment::cast(token).and_then(|comment| comment.kind().doc) == Some(ast::CommentPlacement::Inner) } -#[cfg(test)] -mod tests; diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index 2e0153a180d..c5420f46796 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs @@ -14,7 +14,7 @@ fn foo() {$0} r#" #[cfg(test)] fn foo() { -use bar::Bar; + use bar::Bar; } "#, ImportGranularity::Crate, @@ -32,7 +32,7 @@ fn respects_cfg_attr_const() { r#" #[cfg(test)] const FOO: Bar = { -use bar::Bar; + use bar::Bar; }; "#, ImportGranularity::Crate,