Skip to content

Commit 70842fa

Browse files
Still complete parentheses & method call arguments if there are existing parentheses, but they are after a newline
1 parent debaef8 commit 70842fa

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

crates/ide-completion/src/context/analysis.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -883,9 +883,10 @@ fn classify_name_ref(
883883
},
884884
ast::MethodCallExpr(method) => {
885885
let receiver = find_opt_node_in_file(original_file, method.receiver());
886+
let has_parens = has_parens(&method);
886887
let kind = NameRefKind::DotAccess(DotAccess {
887888
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
888-
kind: DotAccessKind::Method { has_parens: method.arg_list().is_some_and(|it| it.l_paren_token().is_some()) },
889+
kind: DotAccessKind::Method { has_parens },
889890
receiver,
890891
ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) }
891892
});
@@ -1372,7 +1373,7 @@ fn classify_name_ref(
13721373
}
13731374
}
13741375

1375-
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
1376+
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
13761377

13771378
make_path_kind_expr(it.into())
13781379
},
@@ -1401,7 +1402,7 @@ fn classify_name_ref(
14011402
match parent {
14021403
ast::PathType(it) => make_path_kind_type(it.into()),
14031404
ast::PathExpr(it) => {
1404-
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
1405+
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
14051406

14061407
make_path_kind_expr(it.into())
14071408
},
@@ -1559,6 +1560,30 @@ fn classify_name_ref(
15591560
Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
15601561
}
15611562

1563+
/// When writing in the middle of some code the following situation commonly occurs (`|` denotes the cursor):
1564+
/// ```ignore
1565+
/// value.method|
1566+
/// (1, 2, 3)
1567+
/// ```
1568+
/// Here, we want to complete the method parentheses & arguments (if the corresponding settings are on),
1569+
/// but the thing is parsed as a method call with parentheses. Therefore we use heuristics: if the parentheses
1570+
/// are on the next line, consider them non-existent.
1571+
fn has_parens(node: &dyn HasArgList) -> bool {
1572+
let Some(arg_list) = node.arg_list() else { return false };
1573+
if arg_list.l_paren_token().is_none() {
1574+
return false;
1575+
}
1576+
let prev_siblings = iter::successors(arg_list.syntax().prev_sibling_or_token(), |it| {
1577+
it.prev_sibling_or_token()
1578+
});
1579+
prev_siblings
1580+
.take_while(|syntax| syntax.kind().is_trivia())
1581+
.filter_map(|syntax| {
1582+
syntax.into_token().filter(|token| token.kind() == SyntaxKind::WHITESPACE)
1583+
})
1584+
.all(|whitespace| !whitespace.text().contains('\n'))
1585+
}
1586+
15621587
fn pattern_context_for(
15631588
sema: &Semantics<'_, RootDatabase>,
15641589
original_file: &SyntaxNode,

crates/ide-completion/src/tests/expression.rs

+48
Original file line numberDiff line numberDiff line change
@@ -2126,3 +2126,51 @@ fn main() {
21262126
"#]],
21272127
);
21282128
}
2129+
2130+
#[test]
2131+
fn call_parens_with_newline() {
2132+
check_edit(
2133+
"foo",
2134+
r#"
2135+
fn foo(v: i32) {}
2136+
2137+
fn bar() {
2138+
foo$0
2139+
()
2140+
}
2141+
"#,
2142+
r#"
2143+
fn foo(v: i32) {}
2144+
2145+
fn bar() {
2146+
foo(${1:v});$0
2147+
()
2148+
}
2149+
"#,
2150+
);
2151+
check_edit(
2152+
"foo",
2153+
r#"
2154+
struct Foo;
2155+
impl Foo {
2156+
fn foo(&self, v: i32) {}
2157+
}
2158+
2159+
fn bar() {
2160+
Foo.foo$0
2161+
()
2162+
}
2163+
"#,
2164+
r#"
2165+
struct Foo;
2166+
impl Foo {
2167+
fn foo(&self, v: i32) {}
2168+
}
2169+
2170+
fn bar() {
2171+
Foo.foo(${1:v});$0
2172+
()
2173+
}
2174+
"#,
2175+
);
2176+
}

0 commit comments

Comments
 (0)