[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