[CodeCompletion] Support a narrow case for producing trailing closures directly

This adds a narrow special case in code-completion for control-flow-like
methods such as DispatchQueue().sync that are () -> (), to add a new
completion where the trailing closure is immediately expanded rather
than having to invoke placeholder expansion as a second step.

rdar://problem/26628804
This commit is contained in:
Ben Langmuir
2016-07-01 13:53:57 -07:00
parent 20939dd9d0
commit c8f7da4de1
8 changed files with 268 additions and 135 deletions

View File

@@ -1175,8 +1175,6 @@ void CodeCompletionString::getName(raw_ostream &OS) const {
if (FirstTextChunk.hasValue()) {
for (auto C : getChunks().slice(*FirstTextChunk)) {
using ChunkKind = Chunk::ChunkKind;
if (C.getKind() == ChunkKind::BraceStmtWithCursor)
break;
bool shouldPrint = !C.isAnnotation();
switch (C.getKind()) {
@@ -1565,6 +1563,29 @@ protocolForLiteralKind(CodeCompletionLiteralKind kind) {
}
}
/// Whether funcType has a single argument (not including defaulted arguments)
/// that is of type () -> ().
static bool hasTrivialTrailingClosure(const FuncDecl *FD,
AnyFunctionType *funcType) {
unsigned level = FD->isInstanceMember() ? 1 : 0;
auto Args = decomposeParamType(funcType->getInput(), FD, level);
bool OneArg = Args.size() == 1;
if (Args.size() > 1) {
unsigned NonDefault =
std::count_if(Args.begin(), Args.end() - 1, [](const CallArgParam &P) {
return !P.HasDefaultArgument;
});
OneArg = NonDefault == 0;
}
if (OneArg)
if (auto Fn = Args.back().Ty->getAs<AnyFunctionType>())
return Fn->getInput()->isVoid() && Fn->getResult()->isVoid();
return false;
}
/// Build completions by doing visible decl lookup from a context.
class CompletionLookup final : public swift::VisibleDeclConsumer {
CodeCompletionResultSink &Sink;
@@ -2361,8 +2382,15 @@ public:
if (FirstIndex != 0 && !FunctionType->is<ErrorType>())
FunctionType = FunctionType->castTo<AnyFunctionType>()->getResult();
bool trivialTrailingClosure = false;
if (!IsImplicitlyCurriedInstanceMethod && !FunctionType->is<ErrorType>()) {
trivialTrailingClosure = hasTrivialTrailingClosure(
FD, FunctionType->castTo<AnyFunctionType>());
}
// Add the method, possibly including any default arguments.
auto addMethodImpl = [&](bool includeDefaultArgs = true) {
auto addMethodImpl = [&](bool includeDefaultArgs = true,
bool trivialTrailingClosure = false) {
CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResult::ResultKind::Declaration,
@@ -2395,6 +2423,8 @@ public:
Builder.addCallParameter(Ctx.Id_self, FirstInputType,
/*IsVarArg*/ false, true);
Builder.addRightParen();
} else if (trivialTrailingClosure) {
Builder.addBraceStmtWithCursor(" { code }");
} else {
Builder.addLeftParen();
auto AFT = FunctionType->castTo<AnyFunctionType>();
@@ -2427,6 +2457,10 @@ public:
hasInterestingDefaultValues(FD)) {
addMethodImpl(/*includeDefaultArgs*/ false);
}
if (trivialTrailingClosure) {
addMethodImpl(/*includeDefaultArgs=*/false,
/*trivialTrailingClosure=*/true);
}
addMethodImpl();
}