Skip to content

Commit 5001980

Browse files
authored
Merge pull request #71054 from ahoppen/ahoppen/argument-completion
[CodeComplete] Suggest single argument labels if code completion is invoked at start of function call with exiting parameters
2 parents d60a067 + 695e69e commit 5001980

18 files changed

+184
-205
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,8 @@ ERROR(expected_rparen_expr_list,none,
13641364
ERROR(expected_rsquare_expr_list,none,
13651365
"expected ']' in expression list", ())
13661366

1367+
ERROR(expected_label_before_colon,none, "expected argument label before colon", ())
1368+
13671369
// Array literal expressions
13681370
ERROR(expected_rsquare_array_expr,PointsToFirstBadToken,
13691371
"expected ']' in container literal expression", ())

include/swift/IDE/ArgumentCompletion.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
5252
/// True if the completion is a noninitial term in a variadic argument.
5353
bool IsNoninitialVariadic;
5454

55+
/// Whether to suggest the entire functions signature instead of a single
56+
/// argument for this result.
57+
///
58+
/// This is the case if there are no arguments or labels in the call yet and
59+
/// causes us to add a completion result that completes `Point(|)` to
60+
/// `Point(x: <Int>, y: <Int>)`.
61+
bool IncludeSignature;
62+
5563
/// The base type of the call/subscript (null for free functions).
5664
Type BaseType;
5765

@@ -106,14 +114,10 @@ class ArgumentTypeCheckCompletionCallback : public TypeCheckCompletionCallback {
106114
DeclContext *DC)
107115
: CompletionExpr(CompletionExpr), DC(DC) {}
108116

109-
/// \param IncludeSignature Whether to include a suggestion for the entire
110-
/// function signature instead of suggesting individual labels. Used when
111-
/// completing after the opening '(' of a function call \param Loc The
112-
/// location of the code completion token
113117
/// \param IsLabeledTrailingClosure Whether we are completing the label of a
114118
/// labeled trailing closure, ie. if the code completion location is outside
115119
/// the call after the first trailing closure of the call.
116-
void collectResults(bool IncludeSignature, bool IsLabeledTrailingClosure,
120+
void collectResults(bool IsLabeledTrailingClosure,
117121
SourceLoc Loc, DeclContext *DC,
118122
CodeCompletionContext &CompletionCtx);
119123
};

include/swift/IDE/CodeCompletionResult.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ enum class CompletionKind : uint8_t {
195195
StmtOrExpr,
196196
PostfixExprBeginning,
197197
PostfixExpr,
198-
PostfixExprParen,
199198
KeyPathExprObjC,
200199
KeyPathExprSwift,
201200
TypeDeclResultBeginning,

include/swift/Parse/IDEInspectionCallbacks.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,6 @@ class CodeCompletionCallbacks {
170170
/// is completing after set as its base.
171171
virtual void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace){};
172172

173-
/// Complete a given expr-postfix, given that there is a following
174-
/// left parenthesis.
175-
virtual void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) {};
176-
177173
/// Complete the argument to an Objective-C #keyPath
178174
/// expression.
179175
///

include/swift/Parse/Parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,6 +1869,8 @@ class Parser {
18691869
parseArgumentList(tok leftTok, tok rightTok, bool isExprBasic,
18701870
bool allowTrailingClosure = true);
18711871

1872+
ParserStatus parseExprListElement(tok rightTok, bool isArgumentList, SourceLoc leftLoc, SmallVectorImpl<ExprListElt> &elts);
1873+
18721874
/// Parse one or more trailing closures after an argument list.
18731875
ParserStatus parseTrailingClosures(bool isExprBasic, SourceRange calleeRange,
18741876
SmallVectorImpl<Argument> &closures);

lib/IDE/ArgumentCompletion.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,18 @@ void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
278278
}
279279
}
280280

281+
bool IncludeSignature = false;
282+
if (ParentCall->getArgs()->getUnlabeledUnaryExpr() == CompletionExpr) {
283+
// If the code completion expression is the only expression in the call
284+
// and the code completion token doesn’t have a label, we have a case like
285+
// `Point(|)`. Suggest the entire function signature.
286+
IncludeSignature = true;
287+
}
288+
281289
Results.push_back(
282-
{ExpectedTy, ExpectedCallType, isa<SubscriptExpr>(ParentCall),
290+
{ExpectedTy, ExpectedCallType, isa<SubscriptExpr>(ParentCall),
283291
Info.getValue(), FuncTy, ArgIdx, ParamIdx, std::move(ClaimedParams),
284-
IsNoninitialVariadic, Info.BaseTy, HasLabel, FirstTrailingClosureIndex,
292+
IsNoninitialVariadic, IncludeSignature, Info.BaseTy, HasLabel, FirstTrailingClosureIndex,
285293
IsAsync, DeclParamIsOptional, SolutionSpecificVarTypes});
286294
}
287295

@@ -316,7 +324,7 @@ void ArgumentTypeCheckCompletionCallback::computeShadowedDecls(
316324
}
317325

318326
void ArgumentTypeCheckCompletionCallback::collectResults(
319-
bool IncludeSignature, bool IsLabeledTrailingClosure, SourceLoc Loc,
327+
bool IsLabeledTrailingClosure, SourceLoc Loc,
320328
DeclContext *DC, ide::CodeCompletionContext &CompletionCtx) {
321329
ASTContext &Ctx = DC->getASTContext();
322330
CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
@@ -333,13 +341,14 @@ void ArgumentTypeCheckCompletionCallback::collectResults(
333341
}
334342

335343
SmallVector<Type, 8> ExpectedTypes;
344+
SmallVector<PossibleParamInfo, 8> Params;
336345

337-
if (IncludeSignature && !Results.empty()) {
338-
Lookup.setHaveLParen(true);
339-
Lookup.setExpectedTypes(ExpectedCallTypes,
340-
/*isImplicitSingleExpressionReturn=*/false);
346+
for (auto &Result : Results) {
347+
if (Result.IncludeSignature) {
348+
Lookup.setHaveLParen(true);
349+
Lookup.setExpectedTypes(ExpectedCallTypes,
350+
/*isImplicitSingleExpressionReturn=*/false);
341351

342-
for (auto &Result : Results) {
343352
auto SemanticContext = SemanticContextKind::None;
344353
NominalTypeDecl *BaseNominal = nullptr;
345354
if (Result.BaseType) {
@@ -383,19 +392,16 @@ void ArgumentTypeCheckCompletionCallback::collectResults(
383392
}
384393
}
385394
}
386-
}
387-
Lookup.setHaveLParen(false);
388-
389-
shouldPerformGlobalCompletion |=
390-
!Lookup.FoundFunctionCalls || Lookup.FoundFunctionsWithoutFirstKeyword;
391-
} else if (!Results.empty()) {
392-
SmallVector<PossibleParamInfo, 8> Params;
393-
for (auto &Ret : Results) {
395+
Lookup.setHaveLParen(false);
396+
// We didn't find any function signatures. Perform global completion as a fallback.
397+
shouldPerformGlobalCompletion |=
398+
!Lookup.FoundFunctionCalls || Lookup.FoundFunctionsWithoutFirstKeyword;
399+
} else {
394400
shouldPerformGlobalCompletion |=
395-
addPossibleParams(Ret, Params, ExpectedTypes);
401+
addPossibleParams(Result, Params, ExpectedTypes);
396402
}
397-
Lookup.addCallArgumentCompletionResults(Params, IsLabeledTrailingClosure);
398403
}
404+
Lookup.addCallArgumentCompletionResults(Params, IsLabeledTrailingClosure);
399405

400406
if (shouldPerformGlobalCompletion) {
401407
llvm::SmallDenseMap<const VarDecl *, Type> SolutionSpecificVarTypes;

lib/IDE/CodeCompletion.cpp

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
259259
void completeForEachSequenceBeginning(CodeCompletionExpr *E) override;
260260
void completeForEachInKeyword() override;
261261
void completePostfixExpr(CodeCompletionExpr *E, bool hasSpace) override;
262-
void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override;
263262
void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override;
264263

265264
void completeTypeDeclResultBeginning() override;
@@ -419,32 +418,6 @@ void CodeCompletionCallbacksImpl::completePostfixExpr(CodeCompletionExpr *E,
419418
CurDeclContext = P.CurDeclContext;
420419
}
421420

422-
void CodeCompletionCallbacksImpl::completePostfixExprParen(Expr *E,
423-
Expr *CodeCompletionE) {
424-
assert(P.Tok.is(tok::code_complete));
425-
426-
// Don't produce any results in an enum element.
427-
if (InEnumElementRawValue)
428-
return;
429-
430-
Kind = CompletionKind::PostfixExprParen;
431-
ParsedExpr = E;
432-
CurDeclContext = P.CurDeclContext;
433-
CodeCompleteTokenExpr = static_cast<CodeCompletionExpr*>(CodeCompletionE);
434-
435-
ShouldCompleteCallPatternAfterParen = true;
436-
if (CompletionContext.getCallPatternHeuristics()) {
437-
// Lookahead one token to decide what kind of call completions to provide.
438-
// When it appears that there is already code for the call present, just
439-
// complete values and/or argument labels. Otherwise give the entire call
440-
// pattern.
441-
Token next = P.peekToken();
442-
if (!next.isAtStartOfLine() && !next.is(tok::eof) && !next.is(tok::r_paren)) {
443-
ShouldCompleteCallPatternAfterParen = false;
444-
}
445-
}
446-
}
447-
448421
void CodeCompletionCallbacksImpl::completeExprKeyPath(KeyPathExpr *KPE,
449422
SourceLoc DotLoc) {
450423
Kind = (!KPE || KPE->isObjC()) ? CompletionKind::KeyPathExprObjC
@@ -1075,7 +1048,6 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
10751048
break;
10761049

10771050
case CompletionKind::CallArg:
1078-
case CompletionKind::PostfixExprParen:
10791051
// Note that we don't add keywords here as the completion might be for
10801052
// an argument list pattern. We instead add keywords later in
10811053
// CodeCompletionCallbacksImpl::doneParsing when we know we're not
@@ -1554,8 +1526,7 @@ void CodeCompletionCallbacksImpl::postfixCompletion(SourceLoc CompletionLoc,
15541526
Context.CompletionCallback, &Lookup);
15551527
typeCheckContextAt(TypeCheckASTNodeAtLocContext::node(CurDeclContext, AE),
15561528
CompletionLoc);
1557-
Lookup.collectResults(/*IncludeSignature=*/false,
1558-
/*IsLabeledTrailingClosure=*/true, CompletionLoc,
1529+
Lookup.collectResults(/*IsLabeledTrailingClosure=*/true, CompletionLoc,
15591530
CurDeclContext, CompletionContext);
15601531
}
15611532
}
@@ -1599,8 +1570,7 @@ void CodeCompletionCallbacksImpl::callCompletion(SourceLoc CompletionLoc,
15991570
CurDeclContext);
16001571
typeCheckWithLookup(Lookup, CompletionLoc);
16011572

1602-
Lookup.collectResults(ShouldCompleteCallPatternAfterParen,
1603-
/*IsLabeledTrailingClosure=*/false, CompletionLoc,
1573+
Lookup.collectResults(/*IsLabeledTrailingClosure=*/false, CompletionLoc,
16041574
CurDeclContext, CompletionContext);
16051575
Consumer.handleResults(CompletionContext);
16061576
}
@@ -1725,7 +1695,6 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17251695
case CompletionKind::KeyPathExprSwift:
17261696
keyPathExprCompletion(CompletionLoc, MaybeFuncBody);
17271697
return;
1728-
case CompletionKind::PostfixExprParen:
17291698
case CompletionKind::CallArg:
17301699
callCompletion(CompletionLoc, MaybeFuncBody);
17311700
return;
@@ -1773,8 +1742,7 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17731742
ParsedExpr->setType(*ExprType);
17741743
}
17751744

1776-
if (!ExprType && Kind != CompletionKind::PostfixExprParen &&
1777-
Kind != CompletionKind::CallArg &&
1745+
if (!ExprType && Kind != CompletionKind::CallArg &&
17781746
Kind != CompletionKind::KeyPathExprObjC)
17791747
return;
17801748
}
@@ -1810,7 +1778,6 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
18101778
case CompletionKind::AfterPoundExpr:
18111779
case CompletionKind::AccessorBeginning:
18121780
case CompletionKind::CaseStmtBeginning:
1813-
case CompletionKind::PostfixExprParen:
18141781
case CompletionKind::PostfixExpr:
18151782
case CompletionKind::ReturnStmtExpr:
18161783
case CompletionKind::YieldStmtExpr:

lib/Parse/ParseDecl.cpp

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4148,44 +4148,24 @@ ParserResult<CustomAttr> Parser::parseCustomAttribute(
41484148
ParserStatus status;
41494149
ArgumentList *argList = nullptr;
41504150
if (Tok.isFollowingLParen() && isCustomAttributeArgument()) {
4151-
if (peekToken().is(tok::code_complete)) {
4152-
auto lParenLoc = consumeToken(tok::l_paren);
4153-
auto typeE = new (Context) TypeExpr(type.get());
4154-
auto CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
4155-
if (CodeCompletionCallbacks) {
4156-
CodeCompletionCallbacks->completePostfixExprParen(typeE, CCE);
4157-
}
4158-
consumeToken(tok::code_complete);
4159-
skipUntilDeclStmtRBrace(tok::r_paren);
4160-
auto rParenLoc = PreviousLoc;
4161-
if (Tok.is(tok::r_paren)) {
4162-
rParenLoc = consumeToken(tok::r_paren);
4163-
}
4164-
4165-
argList = ArgumentList::createParsed(
4166-
Context, lParenLoc, {Argument::unlabeled(CCE)}, rParenLoc,
4167-
/*trailingClosureIdx=*/llvm::None);
4168-
status.setHasCodeCompletionAndIsError();
4169-
} else {
4170-
// If we have no local context to parse the initial value into, create
4171-
// one for the PBD we'll eventually create. This allows us to have
4172-
// reasonable DeclContexts for any closures that may live inside of
4173-
// initializers.
4174-
llvm::Optional<ParseFunctionBody> initParser;
4175-
if (!CurDeclContext->isLocalContext()) {
4176-
if (!initContext)
4177-
initContext = PatternBindingInitializer::create(CurDeclContext);
4151+
// If we have no local context to parse the initial value into, create
4152+
// one for the PBD we'll eventually create. This allows us to have
4153+
// reasonable DeclContexts for any closures that may live inside of
4154+
// initializers.
4155+
llvm::Optional<ParseFunctionBody> initParser;
4156+
if (!CurDeclContext->isLocalContext()) {
4157+
if (!initContext)
4158+
initContext = PatternBindingInitializer::create(CurDeclContext);
41784159

4179-
initParser.emplace(*this, initContext);
4180-
}
4181-
auto result = parseArgumentList(tok::l_paren, tok::r_paren,
4182-
/*isExprBasic*/ true,
4183-
/*allowTrailingClosure*/ false);
4184-
status |= result;
4185-
argList = result.get();
4186-
assert(!argList->hasAnyTrailingClosures() &&
4187-
"Cannot parse a trailing closure here");
4160+
initParser.emplace(*this, initContext);
41884161
}
4162+
auto result = parseArgumentList(tok::l_paren, tok::r_paren,
4163+
/*isExprBasic*/ true,
4164+
/*allowTrailingClosure*/ false);
4165+
status |= result;
4166+
argList = result.get();
4167+
assert(!argList->hasAnyTrailingClosures() &&
4168+
"Cannot parse a trailing closure here");
41894169
}
41904170

41914171
// Form the attribute.

0 commit comments

Comments
 (0)