[clang-tools-extra] 7f0dcf6 - [clangd] Show lambda signature for lambda autocompletions

Kirill Bobyrev via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 22 03:53:34 PST 2019


Author: Kirill Bobyrev
Date: 2019-11-22T12:48:06+01:00
New Revision: 7f0dcf665dd22be296805bc7a1c71a36243c4e09

URL: https://github.com/llvm/llvm-project/commit/7f0dcf665dd22be296805bc7a1c71a36243c4e09
DIFF: https://github.com/llvm/llvm-project/commit/7f0dcf665dd22be296805bc7a1c71a36243c4e09.diff

LOG: [clangd] Show lambda signature for lambda autocompletions

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.

Reviewers: sammccall

Reviewed by: sammccall

Differential revision: https://reviews.llvm.org/D70445

Added: 
    

Modified: 
    clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
    clang/lib/Sema/SemaCodeComplete.cpp
    clang/test/CodeCompletion/function-templates.cpp
    clang/test/CodeCompletion/lambdas.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 6757a8c686a7..cb6d61150319 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -2465,6 +2465,26 @@ TEST(CompletionTest, NoCompletionsForNewNames) {
   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
index 81eed4330cdc..e75aca4d81e5 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -3315,6 +3315,18 @@ CodeCompletionResult::createCodeCompletionStringForOverride(
   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<VarDecl>(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 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
   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)) {
+  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 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
     AddFunctionParameterChunks(PP, Policy, Function, Result);
     Result.AddChunk(CodeCompletionString::CK_RightParen);
     AddFunctionTypeQualsToCompletionString(Result, Function);
+  };
+
+  if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
+    AddFunctionTypeAndResult(Function);
+    return Result.TakeString();
+  }
+
+  if (const auto *CallOperator =
+          dyn_cast_or_null<FunctionDecl>(extractFunctorCallOperator(ND))) {
+    AddFunctionTypeAndResult(CallOperator);
     return Result.TakeString();
   }
 
+  AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);
+
   if (const FunctionTemplateDecl *FunTmpl =
           dyn_cast<FunctionTemplateDecl>(ND)) {
     AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
@@ -3417,6 +3440,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
     Result.AddChunk(CodeCompletionString::CK_RightAngle);
     return Result.TakeString();
   }
+
   if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND)) {
     Selector Sel = Method->getSelector();
     if (Sel.isUnarySelector()) {

diff  --git a/clang/test/CodeCompletion/function-templates.cpp b/clang/test/CodeCompletion/function-templates.cpp
index cdbbf75838e1..e7123a33133e 100644
--- a/clang/test/CodeCompletion/function-templates.cpp
+++ b/clang/test/CodeCompletion/function-templates.cpp
@@ -1,7 +1,7 @@
 namespace std {
   template<typename RandomAccessIterator>
   void sort(RandomAccessIterator first, RandomAccessIterator last);
-  
+
   template<class X, class Y>
   X* dyn_cast(Y *Val);
 }
@@ -11,13 +11,17 @@ class Foo {
   template<typename T> T &getAs();
 };
 
+template <typename T, typename U, typename V>
+V doSomething(T t, const U &u, V *v) { return V(); }
+
 void f() {
   std::sort(1, 2);
   Foo().getAs<int>();
-  // 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
index 05c47b8c2a4f..3e431a330f49 100644
--- a/clang/test/CodeCompletion/lambdas.cpp
+++ b/clang/test/CodeCompletion/lambdas.cpp
@@ -60,3 +60,15 @@ void test5() {
   // 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#]
+}


        


More information about the cfe-commits mailing list