Index: cfe/trunk/lib/Sema/SemaCodeComplete.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCodeComplete.cpp +++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp @@ -4108,6 +4108,69 @@ Results.ExitScope(); } +/// Try to find a corresponding FunctionProtoType for function-like types (e.g. +/// function pointers, std::function, etc). +static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) { + assert(!T.isNull()); + // Try to extract first template argument from std::function<> and similar. + // Note we only handle the sugared types, they closely match what users wrote. + // We explicitly choose to not handle ClassTemplateSpecializationDecl. + if (auto *Specialization = T->getAs()) { + if (Specialization->getNumArgs() != 1) + return nullptr; + const TemplateArgument &Argument = Specialization->getArg(0); + if (Argument.getKind() != TemplateArgument::Type) + return nullptr; + return Argument.getAsType()->getAs(); + } + // Handle other cases. + if (T->isPointerType()) + T = T->getPointeeType(); + return T->getAs(); +} + +/// Adds a pattern completion for a lambda expression with the specified +/// parameter types and placeholders for parameter names. +static void AddLambdaCompletion(ResultBuilder &Results, + llvm::ArrayRef Parameters, + const LangOptions &LangOpts) { + CodeCompletionBuilder Completion(Results.getAllocator(), + Results.getCodeCompletionTUInfo()); + // []() {} + Completion.AddChunk(CodeCompletionString::CK_LeftBracket); + Completion.AddPlaceholderChunk("="); + Completion.AddChunk(CodeCompletionString::CK_RightBracket); + if (!Parameters.empty()) { + Completion.AddChunk(CodeCompletionString::CK_LeftParen); + bool First = true; + for (auto Parameter : Parameters) { + if (!First) + Completion.AddChunk(CodeCompletionString::ChunkKind::CK_Comma); + else + First = false; + + constexpr llvm::StringLiteral NamePlaceholder = "!#!NAME_GOES_HERE!#!"; + std::string Type = NamePlaceholder; + Parameter.getAsStringInternal(Type, PrintingPolicy(LangOpts)); + llvm::StringRef Prefix, Suffix; + std::tie(Prefix, Suffix) = llvm::StringRef(Type).split(NamePlaceholder); + Prefix = Prefix.rtrim(); + Suffix = Suffix.ltrim(); + + Completion.AddTextChunk(Completion.getAllocator().CopyString(Prefix)); + Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Completion.AddPlaceholderChunk("parameter"); + Completion.AddTextChunk(Completion.getAllocator().CopyString(Suffix)); + }; + Completion.AddChunk(CodeCompletionString::CK_RightParen); + } + Completion.AddChunk(CodeCompletionString::CK_LeftBrace); + Completion.AddPlaceholderChunk("body"); + Completion.AddChunk(CodeCompletionString::CK_RightBrace); + + Results.AddResult(Completion.TakeString()); +} + /// Perform code-completion in an expression context when we know what /// type we're looking for. void Sema::CodeCompleteExpression(Scope *S, @@ -4169,6 +4232,14 @@ if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false, PreferredTypeIsPointer); + + // Complete a lambda expression when preferred type is a function. + if (!Data.PreferredType.isNull() && getLangOpts().CPlusPlus11) { + if (const FunctionProtoType *F = + TryDeconstructFunctionLike(Data.PreferredType)) + AddLambdaCompletion(Results, F->getParamTypes(), getLangOpts()); + } + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } Index: cfe/trunk/test/CodeCompletion/lambdas.cpp =================================================================== --- cfe/trunk/test/CodeCompletion/lambdas.cpp +++ cfe/trunk/test/CodeCompletion/lambdas.cpp @@ -0,0 +1,53 @@ +template +struct function { +}; + + +void test() { + void (*x)(int, double) = nullptr; + + function y = {}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:7:28 %s -o - | FileCheck -check-prefix=CHECK-1 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:9:35 %s -o - | FileCheck -check-prefix=CHECK-1 %s + // CHECK-1: COMPLETION: Pattern : [<#=#>](int <#parameter#>, double <#parameter#>){<#body#>} + + // == Placeholders for suffix types must be placed properly. + function z = {}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:15:36 %s -o - | FileCheck -check-prefix=CHECK-2 %s + // CHECK-2: COMPLETION: Pattern : [<#=#>](void (* <#parameter#>)(int)){<#body#>} + + // == No need for a parameter list if function has no parameters. + function a = {}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:20:24 %s -o - | FileCheck -check-prefix=CHECK-3 %s + // CHECK-3: COMPLETION: Pattern : [<#=#>]{<#body#>} +} + +template +struct vector {}; + +void test2() { + // == Try to preserve types as written. + function)> a = {}; + + using function_typedef = function)>; + function_typedef b = {}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:30:35 %s -o - | FileCheck -check-prefix=CHECK-4 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:33:24 %s -o - | FileCheck -check-prefix=CHECK-4 %s + // CHECK-4: COMPLETION: Pattern : [<#=#>](vector <#parameter#>){<#body#>} +} + +// Check another common function wrapper name. +template struct unique_function {}; + +void test3() { + unique_function a = {}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:43:31 %s -o - | FileCheck -check-prefix=CHECK-5 %s + // CHECK-5: COMPLETION: Pattern : [<#=#>]{<#body#>} +} + +template struct weird_function {}; +void test4() { + weird_function b = {}; + // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:50:35 %s -o - | FileCheck -check-prefix=CHECK-6 %s + // CHECK-6-NOT: COMPLETION: Pattern : [<#= +}