Skip to content

Commit 25cae94

Browse files
Don't complete ; when in closure return expression
Completing it will break syntax.
1 parent ee38991 commit 25cae94

File tree

1 file changed

+58
-24
lines changed
  • src/tools/rust-analyzer/crates/ide-completion/src/render

1 file changed

+58
-24
lines changed

src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
66
use ide_db::{SnippetCap, SymbolKind};
77
use itertools::Itertools;
88
use stdx::{format_to, to_lower_snake_case};
9-
use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, ToSmolStr, T};
9+
use syntax::{ast, format_smolstr, match_ast, AstNode, Edition, SmolStr, SyntaxKind, ToSmolStr, T};
1010

1111
use crate::{
1212
context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind},
@@ -278,31 +278,44 @@ pub(super) fn add_call_parens<'b>(
278278
(snippet, "(…)")
279279
};
280280
if ret_type.is_unit() && ctx.config.add_semicolon_to_unit {
281-
let next_non_trivia_token =
282-
std::iter::successors(ctx.token.next_token(), |it| it.next_token())
283-
.find(|it| !it.kind().is_trivia());
284-
let in_match_arm = ctx.token.parent_ancestors().try_for_each(|ancestor| {
285-
if ast::MatchArm::can_cast(ancestor.kind()) {
286-
ControlFlow::Break(true)
287-
} else if matches!(ancestor.kind(), SyntaxKind::EXPR_STMT | SyntaxKind::BLOCK_EXPR) {
288-
ControlFlow::Break(false)
289-
} else {
290-
ControlFlow::Continue(())
281+
let inside_closure_ret = ctx.token.parent_ancestors().try_for_each(|ancestor| {
282+
match_ast! {
283+
match ancestor {
284+
ast::BlockExpr(_) => ControlFlow::Break(false),
285+
ast::ClosureExpr(_) => ControlFlow::Break(true),
286+
_ => ControlFlow::Continue(())
287+
}
291288
}
292289
});
293-
// FIXME: This will assume expr macros are not inside match, we need to somehow go to the "parent" of the root node.
294-
let in_match_arm = match in_match_arm {
295-
ControlFlow::Continue(()) => false,
296-
ControlFlow::Break(it) => it,
297-
};
298-
let complete_token = if in_match_arm { T![,] } else { T![;] };
299-
if next_non_trivia_token.map(|it| it.kind()) != Some(complete_token) {
300-
cov_mark::hit!(complete_semicolon);
301-
let ch = if in_match_arm { ',' } else { ';' };
302-
if snippet.ends_with("$0") {
303-
snippet.insert(snippet.len() - "$0".len(), ch);
304-
} else {
305-
snippet.push(ch);
290+
291+
if inside_closure_ret != ControlFlow::Break(true) {
292+
let next_non_trivia_token =
293+
std::iter::successors(ctx.token.next_token(), |it| it.next_token())
294+
.find(|it| !it.kind().is_trivia());
295+
let in_match_arm = ctx.token.parent_ancestors().try_for_each(|ancestor| {
296+
if ast::MatchArm::can_cast(ancestor.kind()) {
297+
ControlFlow::Break(true)
298+
} else if matches!(ancestor.kind(), SyntaxKind::EXPR_STMT | SyntaxKind::BLOCK_EXPR)
299+
{
300+
ControlFlow::Break(false)
301+
} else {
302+
ControlFlow::Continue(())
303+
}
304+
});
305+
// FIXME: This will assume expr macros are not inside match, we need to somehow go to the "parent" of the root node.
306+
let in_match_arm = match in_match_arm {
307+
ControlFlow::Continue(()) => false,
308+
ControlFlow::Break(it) => it,
309+
};
310+
let complete_token = if in_match_arm { T![,] } else { T![;] };
311+
if next_non_trivia_token.map(|it| it.kind()) != Some(complete_token) {
312+
cov_mark::hit!(complete_semicolon);
313+
let ch = if in_match_arm { ',' } else { ';' };
314+
if snippet.ends_with("$0") {
315+
snippet.insert(snippet.len() - "$0".len(), ch);
316+
} else {
317+
snippet.push(ch);
318+
}
306319
}
307320
}
308321
}
@@ -886,6 +899,27 @@ fn bar() {
886899
v => foo()$0,
887900
}
888901
}
902+
"#,
903+
);
904+
}
905+
906+
#[test]
907+
fn no_semicolon_in_closure_ret() {
908+
check_edit(
909+
r#"foo"#,
910+
r#"
911+
fn foo() {}
912+
fn baz(_: impl FnOnce()) {}
913+
fn bar() {
914+
baz(|| fo$0);
915+
}
916+
"#,
917+
r#"
918+
fn foo() {}
919+
fn baz(_: impl FnOnce()) {}
920+
fn bar() {
921+
baz(|| foo()$0);
922+
}
889923
"#,
890924
);
891925
}

0 commit comments

Comments
 (0)