Skip to content

Commit c99af83

Browse files
committed
[CodeCompletion] Consolidate parameter list processing funcitons
There were 2 functions to output argument list. Consolidate them and consistently use it from every call like production (i.e. function call, constructor call, enum with associated values, subscript)
1 parent d00dcaa commit c99af83

24 files changed

+393
-392
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 128 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,27 +2028,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
20282028
addTypeAnnotation(Builder, VarType);
20292029
}
20302030

2031-
void addParameters(CodeCompletionResultBuilder &Builder,
2032-
const ParameterList *params) {
2033-
bool NeedComma = false;
2034-
for (auto &param : *params) {
2035-
if (NeedComma)
2036-
Builder.addComma();
2037-
NeedComma = true;
2038-
2039-
Type type = param->getInterfaceType();
2040-
if (param->isVariadic())
2041-
type = ParamDecl::getVarargBaseTy(type);
2042-
2043-
auto isIUO =
2044-
param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
2045-
2046-
Builder.addCallParameter(param->getArgumentName(), type,
2047-
param->isVariadic(), /*Outermost*/ true,
2048-
param->isInOut(), isIUO, param->isAutoClosure());
2049-
}
2050-
}
2051-
20522031
static bool hasInterestingDefaultValues(const AbstractFunctionDecl *func) {
20532032
if (!func) return false;
20542033

@@ -2064,99 +2043,98 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
20642043
return false;
20652044
}
20662045

2067-
// Returns true if any content was added to Builder.
2068-
bool addParamPatternFromFunction(CodeCompletionResultBuilder &Builder,
2069-
const AnyFunctionType *AFT,
2070-
const AbstractFunctionDecl *AFD,
2071-
bool includeDefaultArgs = true) {
2072-
2073-
const ParameterList *BodyParams = nullptr;
2074-
const ParamDecl *SelfDecl = nullptr;
2075-
2076-
if (AFD) {
2077-
BodyParams = AFD->getParameters();
2078-
2079-
// FIXME: Hack because we don't know which parameter list we're
2080-
// actually working with.
2081-
const unsigned expectedNumParams = AFT->getParams().size();
2082-
if (expectedNumParams != BodyParams->size()) {
2083-
BodyParams = nullptr;
2084-
2085-
// Adjust to the "self" list if that is present, otherwise give up.
2086-
if (expectedNumParams == 1 && AFD->getImplicitSelfDecl())
2087-
SelfDecl = AFD->getImplicitSelfDecl();
2088-
BodyParams = nullptr;
2089-
}
2090-
}
2046+
/// Build argument patterns for calling. Returns \c true if any content was
2047+
/// added to \p Builder. If \p declParams is non-empty, the size must match
2048+
/// with \p typeParams.
2049+
bool addCallArgumentPatterns(CodeCompletionResultBuilder &Builder,
2050+
ArrayRef<AnyFunctionType::Param> typeParams,
2051+
ArrayRef<const ParamDecl *> declParams,
2052+
bool includeDefaultArgs = true) {
2053+
assert(declParams.empty() || typeParams.size() == declParams.size());
20912054

20922055
bool modifiedBuilder = false;
20932056

20942057
// Determine whether we should skip this argument because it is defaulted.
2095-
auto shouldSkipArg = [&](unsigned i) -> bool {
2096-
if (!BodyParams || i >= BodyParams->size())
2058+
auto shouldSkipArg = [&](const ParamDecl *PD) -> bool {
2059+
switch (PD->getDefaultArgumentKind()) {
2060+
case DefaultArgumentKind::None:
20972061
return false;
20982062

2099-
switch (BodyParams->get(i)->getDefaultArgumentKind()) {
2100-
case DefaultArgumentKind::None:
2101-
return false;
2102-
2103-
case DefaultArgumentKind::Normal:
2104-
case DefaultArgumentKind::Inherited:
2105-
case DefaultArgumentKind::NilLiteral:
2106-
case DefaultArgumentKind::EmptyArray:
2107-
case DefaultArgumentKind::EmptyDictionary:
2108-
return !includeDefaultArgs;
2109-
2110-
case DefaultArgumentKind::File:
2111-
case DefaultArgumentKind::Line:
2112-
case DefaultArgumentKind::Column:
2113-
case DefaultArgumentKind::Function:
2114-
case DefaultArgumentKind::DSOHandle:
2115-
// Skip parameters that are defaulted to source location or other
2116-
// caller context information. Users typically don't want to specify
2117-
// these parameters.
2118-
return true;
2063+
case DefaultArgumentKind::Normal:
2064+
case DefaultArgumentKind::Inherited:
2065+
case DefaultArgumentKind::NilLiteral:
2066+
case DefaultArgumentKind::EmptyArray:
2067+
case DefaultArgumentKind::EmptyDictionary:
2068+
return !includeDefaultArgs;
2069+
2070+
case DefaultArgumentKind::File:
2071+
case DefaultArgumentKind::Line:
2072+
case DefaultArgumentKind::Column:
2073+
case DefaultArgumentKind::Function:
2074+
case DefaultArgumentKind::DSOHandle:
2075+
// Skip parameters that are defaulted to source location or other
2076+
// caller context information. Users typically don't want to specify
2077+
// these parameters.
2078+
return true;
21192079
}
21202080

21212081
llvm_unreachable("Unhandled DefaultArgumentKind in switch.");
21222082
};
21232083

21242084
bool NeedComma = false;
21252085
// Iterate over each parameter.
2126-
for (unsigned i = 0, e = AFT->getParams().size(); i != e; ++i) {
2127-
// If we should skip this argument, do so.
2128-
if (shouldSkipArg(i)) continue;
2086+
for (unsigned i = 0; i != typeParams.size(); ++i) {
2087+
auto &typeParam = typeParams[i];
21292088

2130-
const auto &Param = AFT->getParams()[i];
2131-
auto ParamType = Param.isVariadic()
2132-
? ParamDecl::getVarargBaseTy(Param.getPlainType())
2133-
: Param.getPlainType();
2089+
Identifier argName;
2090+
Identifier bodyName;
2091+
bool isIUO = false;
21342092

2135-
if (NeedComma)
2136-
Builder.addComma();
2137-
if (BodyParams || SelfDecl) {
2138-
auto *PD = (BodyParams ? BodyParams->get(i) : SelfDecl);
2139-
2140-
// If we have a local name for the parameter, pass in that as well.
2141-
auto argName = PD->getArgumentName();
2142-
auto bodyName = PD->getName();
2143-
auto isIUO =
2144-
PD->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
2145-
Builder.addCallParameter(argName, bodyName, ParamType,
2146-
Param.isVariadic(), /*TopLevel*/ true,
2147-
Param.isInOut(), isIUO, Param.isAutoClosure());
2093+
if (!declParams.empty()) {
2094+
auto *PD = declParams[i];
2095+
if (shouldSkipArg(PD))
2096+
continue;
2097+
argName = PD->getArgumentName();
2098+
bodyName = PD->getParameterName();
2099+
isIUO = PD->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
21482100
} else {
2149-
Builder.addCallParameter(
2150-
Param.getLabel(), ParamType, Param.isVariadic(), /*TopLevel*/ true,
2151-
Param.isInOut(), /*isIUO*/ false, Param.isAutoClosure());
2101+
isIUO = false;
2102+
argName = typeParam.getLabel();
21522103
}
2104+
2105+
bool isVariadic = typeParam.isVariadic();
2106+
bool isInOut = typeParam.isInOut();
2107+
bool isAutoclosure = typeParam.isAutoClosure();
2108+
Type paramTy = typeParam.getPlainType();
2109+
if (isVariadic)
2110+
paramTy = ParamDecl::getVarargBaseTy(paramTy);
2111+
2112+
if (NeedComma)
2113+
Builder.addComma();
2114+
2115+
Builder.addCallParameter(argName, bodyName, paramTy, isVariadic,
2116+
/*TopLevel*/ true, isInOut, isIUO,
2117+
isAutoclosure);
2118+
21532119
modifiedBuilder = true;
21542120
NeedComma = true;
21552121
}
2156-
21572122
return modifiedBuilder;
21582123
}
21592124

2125+
/// Build argument patterns for calling. Returns \c true if any content was
2126+
/// added to \p Builder. If \p Params is non-nullptr, \F
2127+
bool addCallArgumentPatterns(CodeCompletionResultBuilder &Builder,
2128+
const AnyFunctionType *AFT,
2129+
const ParameterList *Params,
2130+
bool includeDefaultArgs = true) {
2131+
ArrayRef<const ParamDecl *> declParams;
2132+
if (Params)
2133+
declParams = Params->getArray();
2134+
return addCallArgumentPatterns(Builder, AFT->getParams(), declParams,
2135+
includeDefaultArgs);
2136+
}
2137+
21602138
static void addThrows(CodeCompletionResultBuilder &Builder,
21612139
const AnyFunctionType *AFT,
21622140
const AbstractFunctionDecl *AFD) {
@@ -2226,13 +2204,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
22262204

22272205
void addFunctionCallPattern(const AnyFunctionType *AFT,
22282206
const AbstractFunctionDecl *AFD = nullptr) {
2229-
if (AFD)
2230-
foundFunction(AFD);
2231-
else
2232-
foundFunction(AFT);
22332207

22342208
// Add the pattern, possibly including any default arguments.
2235-
auto addPattern = [&](bool includeDefaultArgs = true) {
2209+
auto addPattern = [&](ArrayRef<const ParamDecl *> declParams = {},
2210+
bool includeDefaultArgs = true) {
22362211
// FIXME: to get the corect semantic context we need to know how lookup
22372212
// would have found the declaration AFD. For now, just choose a reasonable
22382213
// default, it's most likely to be CurrentModule or CurrentNominal.
@@ -2244,7 +2219,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
22442219
else
22452220
Builder.addAnnotatedLeftParen();
22462221

2247-
bool anyParam = addParamPatternFromFunction(Builder, AFT, AFD, includeDefaultArgs);
2222+
bool anyParam = addCallArgumentPatterns(Builder, AFT->getParams(),
2223+
declParams, includeDefaultArgs);
22482224

22492225
if (HaveLParen && !anyParam) {
22502226
// Empty result, don't add it.
@@ -2268,10 +2244,49 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
22682244
addTypeAnnotation(Builder, AFT->getResult());
22692245
};
22702246

2271-
if (hasInterestingDefaultValues(AFD))
2272-
addPattern(/*includeDefaultArgs*/ false);
2273-
addPattern();
2247+
if (!AFD || !AFD->hasInterfaceType() ||
2248+
!AFD->getInterfaceType()->is<AnyFunctionType>()) {
2249+
// Probably, calling closure type expression.
2250+
foundFunction(AFT);
2251+
addPattern();
2252+
return;
2253+
} else {
2254+
// Calling function or method.
2255+
foundFunction(AFD);
2256+
2257+
// FIXME: Hack because we don't know we are calling instance
2258+
// method or not. There's invariant that funcTy is derived from AFD.
2259+
// Only if we are calling instance method on meta type, AFT is still
2260+
// curried. So we should be able to detect that by comparing curried level
2261+
// of AFT and the interface type of AFD.
2262+
auto getCurriedLevel = [](const AnyFunctionType *funcTy) -> unsigned {
2263+
unsigned level = 0;
2264+
while ((funcTy = funcTy->getResult()->getAs<AnyFunctionType>()))
2265+
++level;
2266+
return level;
2267+
};
2268+
bool isImplicitlyCurriedInstanceMethod =
2269+
(AFD->hasImplicitSelfDecl() &&
2270+
getCurriedLevel(AFT) ==
2271+
getCurriedLevel(
2272+
AFD->getInterfaceType()->castTo<AnyFunctionType>()) &&
2273+
// NOTE: shouldn't be necessary, but just in case curried level check
2274+
// is insufficient.
2275+
AFT->getParams().size() == 1 &&
2276+
AFT->getParams()[0].getLabel().empty());
2277+
2278+
if (isImplicitlyCurriedInstanceMethod) {
2279+
addPattern({AFD->getImplicitSelfDecl()}, /*includeDefaultArgs=*/true);
2280+
} else {
2281+
if (hasInterestingDefaultValues(AFD))
2282+
addPattern(AFD->getParameters()->getArray(),
2283+
/*includeDefaultArgs=*/false);
2284+
addPattern(AFD->getParameters()->getArray(),
2285+
/*includeDefaultArgs=*/true);
2286+
}
2287+
}
22742288
}
2289+
22752290
bool isImplicitlyCurriedInstanceMethod(const AbstractFunctionDecl *FD) {
22762291
switch (Kind) {
22772292
case LookupKind::ValueExpr:
@@ -2359,17 +2374,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
23592374
auto AFT = FunctionType->castTo<AnyFunctionType>();
23602375
if (IsImplicitlyCurriedInstanceMethod) {
23612376
Builder.addLeftParen();
2362-
auto SelfParam = AFT->getParams()[0];
2363-
Builder.addCallParameter(Ctx.Id_self, SelfParam.getPlainType(),
2364-
/*IsVarArg*/ false, /*TopLevel*/ true,
2365-
SelfParam.isInOut(),
2366-
/*isIUO*/ false, /*isAutoClosure*/ false);
2377+
addCallArgumentPatterns(Builder, AFT->getParams(),
2378+
{FD->getImplicitSelfDecl()},
2379+
includeDefaultArgs);
23672380
Builder.addRightParen();
23682381
} else if (trivialTrailingClosure) {
23692382
Builder.addBraceStmtWithCursor(" { code }");
23702383
} else {
23712384
Builder.addLeftParen();
2372-
addParamPatternFromFunction(Builder, AFT, FD, includeDefaultArgs);
2385+
addCallArgumentPatterns(Builder, AFT, FD->getParameters(),
2386+
includeDefaultArgs);
23732387
Builder.addRightParen();
23742388
addThrows(Builder, AFT, FD);
23752389
}
@@ -2465,8 +2479,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
24652479
else
24662480
Builder.addAnnotatedLeftParen();
24672481

2468-
bool anyParam = addParamPatternFromFunction(Builder, ConstructorType, CD,
2469-
includeDefaultArgs);
2482+
bool anyParam = addCallArgumentPatterns(
2483+
Builder, ConstructorType, CD->getParameters(), includeDefaultArgs);
24702484

24712485
if (HaveLParen && !anyParam) {
24722486
// Empty result, don't add it.
@@ -2549,7 +2563,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
25492563
}
25502564

25512565
Builder.addLeftBracket();
2552-
addParameters(Builder, SD->getIndices());
2566+
addCallArgumentPatterns(Builder,
2567+
getTypeOfMember(SD)->castTo<AnyFunctionType>(),
2568+
SD->getIndices(), true);
25532569
Builder.addRightBracket();
25542570

25552571
// Add a type annotation.
@@ -2666,6 +2682,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26662682
Builder.setAssociatedDecl(EED);
26672683
setClangDeclKeywords(EED, Pairs, Builder);
26682684
addLeadingDot(Builder);
2685+
26692686
Builder.addTextChunk(EED->getName().str());
26702687

26712688
// Enum element is of function type; (Self.type) -> Self or
@@ -2676,8 +2693,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26762693

26772694
if (EnumType->is<FunctionType>()) {
26782695
Builder.addLeftParen();
2679-
addParamPatternFromFunction(Builder, EnumType->castTo<FunctionType>(),
2680-
nullptr);
2696+
addCallArgumentPatterns(Builder, EnumType->castTo<FunctionType>(),
2697+
EED->getParameterList());
26812698
Builder.addRightParen();
26822699

26832700
// Extract result as the enum type.

lib/IDE/CodeCompletionResultBuilder.h

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -322,26 +322,20 @@ class CodeCompletionResultBuilder {
322322
addSimpleChunk(CodeCompletionString::Chunk::ChunkKind::CallParameterBegin);
323323

324324
if (!Name.empty()) {
325-
StringRef NameStr = Name.str();
326-
327-
// 'self' is a keyword, we cannot allow to insert it into the source
328-
// buffer.
329-
bool IsAnnotation = (NameStr == "self");
330-
331325
llvm::SmallString<16> EscapedKeyword;
332326
addChunkWithText(
333327
CodeCompletionString::Chunk::ChunkKind::CallParameterName,
334-
// if the name is not annotation, we need to escape keyword
335-
IsAnnotation ? NameStr
336-
: escapeArgumentLabel(NameStr, !Outermost,
337-
EscapedKeyword));
338-
if (IsAnnotation)
339-
getLastChunk().setIsAnnotation();
340-
328+
escapeArgumentLabel(Name.str(), !Outermost, EscapedKeyword));
329+
addChunkWithTextNoCopy(
330+
CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": ");
331+
} else if (!LocalName.empty()) {
332+
// Use local (non-API) parameter name if we have nothing else.
333+
llvm::SmallString<16> EscapedKeyword;
334+
addChunkWithText(
335+
CodeCompletionString::Chunk::ChunkKind::CallParameterInternalName,
336+
escapeArgumentLabel(LocalName.str(), !Outermost, EscapedKeyword));
341337
addChunkWithTextNoCopy(
342338
CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": ");
343-
if (IsAnnotation)
344-
getLastChunk().setIsAnnotation();
345339
}
346340

347341
// 'inout' arguments are printed specially.
@@ -351,16 +345,6 @@ class CodeCompletionResultBuilder {
351345
Ty = Ty->getInOutObjectType();
352346
}
353347

354-
if (Name.empty() && !LocalName.empty()) {
355-
llvm::SmallString<16> EscapedKeyword;
356-
// Use local (non-API) parameter name if we have nothing else.
357-
addChunkWithText(
358-
CodeCompletionString::Chunk::ChunkKind::CallParameterInternalName,
359-
escapeArgumentLabel(LocalName.str(), !Outermost, EscapedKeyword));
360-
addChunkWithTextNoCopy(
361-
CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": ");
362-
}
363-
364348
// If the parameter is of the type @autoclosure ()->output, then the
365349
// code completion should show the parameter of the output type
366350
// instead of the function type ()->output.

0 commit comments

Comments
 (0)