kbobyrev created this revision. kbobyrev added a reviewer: sammccall. kbobyrev added projects: clang, clang-tools-extra. Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman, jkorous, MaskRay.
The original bug report can be found here <https://github.com/clangd/clangd/issues/85>. Given the following code: c++ void function() { auto Lambda = [](int a, double &b) {return 1.f;}; La^ } Triggering the completion at `^` would show `(lambda)` before this patch and would show signature `(int a, double &b) const`, build a snippet etc with this patch. Repository: rC Clang https://reviews.llvm.org/D70445 Files: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp clang/lib/Sema/SemaCodeComplete.cpp 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<VarDecl>(ND); + if (!VD) + return nullptr; + const auto *LambdaType = VD->getType().getTypePtr(); + if (const auto *SugaredType = dyn_cast<AutoType>(LambdaType)) + LambdaType = SugaredType->desugar().getTypePtr(); + LambdaType = dyn_cast<RecordType>(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<AnnotateAttr>()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); - AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); - - if (const auto *Function = dyn_cast<FunctionDecl>(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<FunctionDecl>(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<FunctionTemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 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<VarDecl>(ND); + if (!VD) + return nullptr; + const auto *LambdaType = VD->getType().getTypePtr(); + if (const auto *SugaredType = dyn_cast<AutoType>(LambdaType)) + LambdaType = SugaredType->desugar().getTypePtr(); + LambdaType = dyn_cast<RecordType>(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<AnnotateAttr>()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); - AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); - - if (const auto *Function = dyn_cast<FunctionDecl>(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<FunctionDecl>(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<FunctionTemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits