Skip to content

Commit 3d05173

Browse files
committed
[CodeCompletion] Always suggest call pattern for nested function calls
When completing in cases like `bar(arg: foo(|, option: 1)`, we don’t know if `option` belongs to the call to `foo` or `bar`. Be defensive and also suggest the signature.
1 parent 9607e9d commit 3d05173

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

lib/IDE/ArgumentCompletion.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@ static bool isExpressionResultTypeUnconstrained(const Solution &S, Expr *E) {
126126
}
127127
}
128128

129+
/// Returns whether `E` has a parent expression with arguments.
130+
static bool hasParentCallLikeExpr(Expr *E, ConstraintSystem &CS) {
131+
E = CS.getParentExpr(E);
132+
while (E) {
133+
if (E->getArgs() || isa<ParenExpr>(E) || isa<TupleExpr>(E) || isa<CollectionExpr>(E)) {
134+
return true;
135+
}
136+
E = CS.getParentExpr(E);
137+
}
138+
return false;
139+
}
140+
129141
void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
130142
Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);
131143

@@ -284,6 +296,14 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
284296
// and the code completion token doesn’t have a label, we have a case like
285297
// `Point(|)`. Suggest the entire function signature.
286298
IncludeSignature = true;
299+
} else if (!ParentCall->getArgs()->empty() &&
300+
ParentCall->getArgs()->getExpr(0) == CompletionExpr) {
301+
if (hasParentCallLikeExpr(ParentCall, CS)) {
302+
// We are completing in cases like `bar(arg: foo(|, option: 1)`
303+
// In these cases, we don’t know if `option` belongs to the call to `foo`
304+
// or `bar`. Be defensive and also suggest the signature.
305+
IncludeSignature = true;
306+
}
287307
}
288308

289309
Results.push_back(

test/IDE/complete_call_arg.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,3 +1407,38 @@ struct AtStartOfFunctionCallWithExistingParams {
14071407
// AT_START_OF_CALL_ONE_EXISTING_ARGUMENT-DAG: Pattern/Local/Flair[ArgLabels]: {#a: Int#}[#Int#]; name=a:
14081408
}
14091409
}
1410+
1411+
struct NestedCallsWithoutClosingParen {
1412+
func foo(arg: Int, arg2: Int) -> Int { 1 }
1413+
func bar(arg: Int, option: Int) -> Int { 1 }
1414+
1415+
func test() {
1416+
bar(arg: foo(#^NESTED_CALL_AT_START^#, option: 1)
1417+
// NESTED_CALL_AT_START-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#arg: Int#}, {#arg2: Int#}[')'][#Int#];
1418+
1419+
bar(arg: 1 + foo(#^NESTED_CALL_IN_BINARY_OP?check=NESTED_CALL_AT_START^#, option: 1)
1420+
1421+
bar(arg: foo(#^NESTED_CALL_AFTER_MEMBER_ACCESS?check=NESTED_CALL_AT_START^#, option: 1)
1422+
1423+
bar(arg: foo(arg: 1, #^NESTED_CALL_AT_SECOND_ARG^#, option: 1)
1424+
// NESTED_CALL_AT_SECOND_ARG-DAG: Pattern/Local/Flair[ArgLabels]: {#arg2: Int#}[#Int#];
1425+
}
1426+
1427+
func testInDictionaryLiteral() {
1428+
let a = 1
1429+
let b = 2
1430+
_ = [a: foo(#^IN_DICTIONARY_LITERAL?check=NESTED_CALL_AT_START^#, b: 1]
1431+
}
1432+
1433+
func testInArrayLiteral() {
1434+
_ = [foo(#^IN_ARRAY_LITERAL?check=NESTED_CALL_AT_START^#, 1]
1435+
}
1436+
1437+
func testInParen() {
1438+
_ = (foo(#^IN_PAREN?check=NESTED_CALL_AT_START^#)
1439+
}
1440+
1441+
func testInTuple() {
1442+
_ = (foo(#^IN_TUPLE?check=NESTED_CALL_AT_START^#, 1)
1443+
}
1444+
}

test/SourceKit/CodeComplete/complete_call_pattern.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ func test() {
99

1010
// RUN: %sourcekitd-test -req=complete -pos=7:11 %s -- %s | %FileCheck %s
1111
// RUN: %sourcekitd-test -req=complete.open -pos=7:11 %s -- %s | %FileCheck %s
12-
// RUN: %sourcekitd-test -req=complete.open -pos=7:11 %s -- %s | %FileCheck %s
1312

14-
// CHECK: key.kind: source.lang.swift.pattern
13+
// CHECK: key.kind: source.lang.swift.decl.function.constructor
1514
// CHECK-NEXT: key.name: "foo:"

0 commit comments

Comments
 (0)