diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -2465,6 +2465,26 @@ EXPECT_THAT(Results.Completions, UnorderedElementsAre()); } +TEST(CompletionTest, Lambda) { + clangd::CodeCompleteOptions Opts = {}; + + auto Results = completions(R"cpp( + void function() { + auto Lambda = [](int a, const double &b) {return 1.f;}; + Lam^ + } + )cpp", + {}, Opts); + + ASSERT_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, ObjectiveCMethodNoArguments) { auto Results = completions(R"objc( @interface Foo diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -3315,6 +3315,18 @@ return Result.TakeString(); } +// FIXME: Right now this works well with lambdas. Add support for other functor +// types like std::function. +static const NamedDecl *extractFunctorCallOperator(const NamedDecl *ND) { + const auto *VD = dyn_cast(ND); + if (!VD) + return nullptr; + const auto *RecordDecl = VD->getType()->getAsCXXRecordDecl(); + if (!RecordDecl || !RecordDecl->isLambda()) + return nullptr; + return RecordDecl->getLambdaCallOperator(); +} + CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, bool IncludeBriefComments, const CodeCompletionContext &CCContext, @@ -3339,9 +3351,8 @@ 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)) { + auto AddFunctionTypeAndResult = [&](const FunctionDecl *Function) { + AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result); AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); AddTypedNameChunk(Ctx, Policy, ND, Result); @@ -3349,9 +3360,21 @@ AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); + }; + + if (const auto *Function = dyn_cast(ND)) { + AddFunctionTypeAndResult(Function); + return Result.TakeString(); + } + + if (const auto *CallOperator = + dyn_cast_or_null(extractFunctorCallOperator(ND))) { + AddFunctionTypeAndResult(CallOperator); return Result.TakeString(); } + AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); + if (const FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, @@ -3417,6 +3440,7 @@ Result.AddChunk(CodeCompletionString::CK_RightAngle); return Result.TakeString(); } + if (const auto *Method = dyn_cast(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { diff --git a/clang/test/CodeCompletion/function-templates.cpp b/clang/test/CodeCompletion/function-templates.cpp --- a/clang/test/CodeCompletion/function-templates.cpp +++ b/clang/test/CodeCompletion/function-templates.cpp @@ -1,7 +1,7 @@ namespace std { template void sort(RandomAccessIterator first, RandomAccessIterator last); - + template X* dyn_cast(Y *Val); } @@ -11,13 +11,17 @@ template T &getAs(); }; +template +V doSomething(T t, const U &u, V *v) { return V(); } + void f() { std::sort(1, 2); Foo().getAs(); - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:15:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:18:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: dyn_cast<<#class X#>>(<#Y *Val#>) // CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#> - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:16:9 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: getAs<<#typename T#>>() -) - + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:22 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s + // CHECK-CC3: [#V#]doSomething(<#T t#>, <#const U &u#>, <#V *v#>) +} diff --git a/clang/test/CodeCompletion/lambdas.cpp b/clang/test/CodeCompletion/lambdas.cpp --- a/clang/test/CodeCompletion/lambdas.cpp +++ b/clang/test/CodeCompletion/lambdas.cpp @@ -60,3 +60,15 @@ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:57:24 %s -o - | FileCheck -check-prefix=CHECK-8 %s // CHECK-8-NOT: COMPLETION: Pattern : [<#= } + +void test6() { + auto my_lambda = [&](int a, double &b) { return 1.f; }; + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:65:58 %s -o - | FileCheck -check-prefix=CHECK-9 %s + // CHECK-9: [#float#]my_lambda(<#int a#>, <#double &b#>)[# const#] +} + +void test7() { + auto generic_lambda = [&](auto a, const auto &b) { return a + b; }; + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:71:70 %s -o - | FileCheck -check-prefix=CHECK-10 %s + // CHECK-10: [#auto#]generic_lambda(<#auto a#>, <#const auto &b#>)[# const#] +}