Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -2471,6 +2471,26 @@ EXPECT_THAT(C, ElementsAre(SnippetSuffix(""))); } +TEST(CompletionTest, Lambda) { + clangd::CodeCompleteOptions Opts = {}; + Opts.AllScopes = true; + + auto Results = completions(R"cpp( + void function() { + auto Lambda = [](int a, const double &b) {return 1.f;}; + Lam^ + } + )cpp", {}, Opts); + + EXPECT_EQ(Results.Completions.size(), 1u); + const auto A = Results.Completions.front(); + EXPECT_EQ(A.Name, "Lambda"); + EXPECT_EQ(A.Signature, "(int a, const double &b) const"); + EXPECT_EQ(A.Kind, CompletionItemKind::Variable); + EXPECT_EQ(A.ReturnType, "float"); + EXPECT_EQ(A.SnippetSuffix, "(${1:int a}, ${2:const double &b})"); +} + TEST(CompletionTest, ObjectiveCMethodOneArgument) { auto Results = completions(R"objc( @interface Foo Index: clang/lib/Sema/SemaCodeComplete.cpp =================================================================== --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -3327,6 +3327,26 @@ return Result.TakeString(); } +namespace { +const CXXMethodDecl *extractLambdaCallOperator(const NamedDecl *ND) { + const auto *VD = dyn_cast(ND); + if (!VD) + return nullptr; + const auto *LambdaType = VD->getType().getTypePtr(); + if (const auto *SugaredType = dyn_cast(LambdaType)) + LambdaType = SugaredType->desugar().getTypePtr(); + LambdaType = dyn_cast(LambdaType); + if (!LambdaType) + return nullptr; + const auto *RecordDecl = LambdaType->getAsCXXRecordDecl(); + // FIXME: Don't ignore generic lambdas. + return (RecordDecl && RecordDecl->isLambda() && + !RecordDecl->isGenericLambda()) + ? RecordDecl->getLambdaCallOperator() + : nullptr; +} +} // namespace + CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, bool IncludeBriefComments, const CodeCompletionContext &CCContext, @@ -3351,19 +3371,30 @@ for (const auto *I : ND->specific_attrs()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); - AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); - - if (const auto *Function = dyn_cast(ND)) { - AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - Ctx, Policy); + auto handleFunctionlike = [&](const FunctionDecl *Function, + bool AddQualifier = true) { + AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result); + if (AddQualifier) + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + Ctx, Policy); AddTypedNameChunk(Ctx, Policy, ND, Result); Result.AddChunk(CodeCompletionString::CK_LeftParen); AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); + }; + + if (const auto *Function = dyn_cast(ND)) { + return handleFunctionlike(Function); } + if (const auto *CallOperator = extractLambdaCallOperator(ND)) { + return handleFunctionlike(CallOperator, false); + } + + AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); + if (const FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,