[clang-tools-extra] r363237 - [clangd] Treat lambdas as functions when preparing hover response

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 13 01:51:44 PDT 2019


Author: kadircet
Date: Thu Jun 13 01:51:44 2019
New Revision: 363237

URL: http://llvm.org/viewvc/llvm-project?rev=363237&view=rev
Log:
[clangd] Treat lambdas as functions when preparing hover response

Reviewers: sammccall, ilya-biryukov

Subscribers: MaskRay, jkorous, arphaman, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D62814

Modified:
    clang-tools-extra/trunk/clangd/XRefs.cpp
    clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp

Modified: clang-tools-extra/trunk/clangd/XRefs.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/XRefs.cpp?rev=363237&r1=363236&r2=363237&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/XRefs.cpp (original)
+++ clang-tools-extra/trunk/clangd/XRefs.cpp Thu Jun 13 01:51:44 2019
@@ -19,7 +19,9 @@
 #include "index/SymbolLocation.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -620,6 +622,23 @@ static llvm::Optional<Range> getTokenRan
                          CharSourceRange::getCharRange(Loc, End));
 }
 
+static const FunctionDecl *getUnderlyingFunction(const Decl *D) {
+  // Extract lambda from variables.
+  if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
+    auto QT = VD->getType();
+    if (!QT.isNull()) {
+      while (!QT->getPointeeType().isNull())
+        QT = QT->getPointeeType();
+
+      if (const auto *CD = QT->getAsCXXRecordDecl())
+        return CD->getLambdaCallOperator();
+    }
+  }
+
+  // Non-lambda functions.
+  return D->getAsFunction();
+}
+
 /// Generate a \p Hover object given the declaration \p D.
 static HoverInfo getHoverContents(const Decl *D) {
   HoverInfo HI;
@@ -654,27 +673,21 @@ static HoverInfo getHoverContents(const
   }
 
   // Fill in types and params.
-  if (const FunctionDecl *FD = D->getAsFunction()) {
+  if (const FunctionDecl *FD = getUnderlyingFunction(D)) {
     HI.ReturnType.emplace();
-    llvm::raw_string_ostream OS(*HI.ReturnType);
-    FD->getReturnType().print(OS, Policy);
-
-    HI.Type.emplace();
-    llvm::raw_string_ostream TypeOS(*HI.Type);
-    FD->getReturnType().print(TypeOS, Policy);
-    TypeOS << '(';
+    {
+      llvm::raw_string_ostream OS(*HI.ReturnType);
+      FD->getReturnType().print(OS, Policy);
+    }
 
     HI.Parameters.emplace();
     for (const ParmVarDecl *PVD : FD->parameters()) {
-      if (HI.Parameters->size())
-        TypeOS << ", ";
       HI.Parameters->emplace_back();
       auto &P = HI.Parameters->back();
       if (!PVD->getType().isNull()) {
         P.Type.emplace();
         llvm::raw_string_ostream OS(*P.Type);
         PVD->getType().print(OS, Policy);
-        PVD->getType().print(TypeOS, Policy);
       } else {
         std::string Param;
         llvm::raw_string_ostream OS(Param);
@@ -690,11 +703,17 @@ static HoverInfo getHoverContents(const
         PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
       }
     }
-    TypeOS << ')';
+
+    HI.Type.emplace();
+    llvm::raw_string_ostream TypeOS(*HI.Type);
+    // Lambdas
+    if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
+      VD->getType().getDesugaredType(D->getASTContext()).print(TypeOS, Policy);
+    // Functions
+    else
+      FD->getType().print(TypeOS, Policy);
     // FIXME: handle variadics.
   } else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
-    // FIXME: Currently lambdas are also handled as ValueDecls, they should be
-    // more similar to functions.
     HI.Type.emplace();
     llvm::raw_string_ostream OS(*HI.Type);
     VD->getType().print(OS, Policy);

Modified: clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp?rev=363237&r1=363236&r2=363237&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp Thu Jun 13 01:51:44 2019
@@ -22,6 +22,7 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include <string>
 
 namespace clang {
 namespace clangd {
@@ -588,7 +589,7 @@ TEST(Hover, Structured) {
          HI.Documentation = "Best foo ever.";
          HI.Definition = "void foo()";
          HI.ReturnType = "void";
-         HI.Type = "void()";
+         HI.Type = "void ()";
          HI.Parameters.emplace();
        }},
       // Inside namespace
@@ -605,7 +606,7 @@ TEST(Hover, Structured) {
          HI.Documentation = "Best foo ever.";
          HI.Definition = "void foo()";
          HI.ReturnType = "void";
-         HI.Type = "void()";
+         HI.Type = "void ()";
          HI.Parameters.emplace();
        }},
       // Field
@@ -733,7 +734,7 @@ class Foo {})cpp";
           bool Q = false, class... Ts>
 void foo())cpp";
          HI.ReturnType = "void";
-         HI.Type = "void()";
+         HI.Type = "void ()";
          HI.Parameters.emplace();
          HI.TemplateParameters = {
              {std::string("template <typename, bool...> class"),
@@ -759,12 +760,76 @@ void foo())cpp";
          HI.Kind = SymbolKind::Function;
          HI.Definition = "Foo<bool, true, false> foo(int, bool T = false)";
          HI.ReturnType = "Foo<bool, true, false>";
-         HI.Type = "Foo<bool, true, false>(int, bool)";
+         HI.Type = "Foo<bool, true, false> (int, bool)";
          HI.Parameters = {
              {std::string("int"), llvm::None, llvm::None},
              {std::string("bool"), std::string("T"), std::string("false")},
          };
        }},
+      // Pointers to lambdas
+      {R"cpp(
+        void foo() {
+          auto lamb = [](int T, bool B) -> bool { return T && B; };
+          auto *b = &lamb;
+          auto *[[^c]] = &b;
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "c";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "auto *c = &b";
+         HI.Type = "class (lambda) **";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
+      // Lambda parameter with decltype reference
+      {R"cpp(
+        auto lamb = [](int T, bool B) -> bool { return T && B; };
+        void foo(decltype(lamb)& bar) {
+          [[ba^r]](0, false);
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "decltype(lamb) &bar";
+         HI.Type = "decltype(lamb) &";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
+      // Lambda parameter with decltype
+      {R"cpp(
+        auto lamb = [](int T, bool B) -> bool { return T && B; };
+        void foo(decltype(lamb) bar) {
+          [[ba^r]](0, false);
+        }
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.LocalScope = "foo::";
+         HI.Name = "bar";
+         HI.Kind = SymbolKind::Variable;
+         HI.Definition = "decltype(lamb) bar";
+         HI.Type = "class (lambda)";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
+         return HI;
+       }},
       // Lambda variable
       {R"cpp(
         void foo() {
@@ -779,7 +844,12 @@ void foo())cpp";
          HI.Name = "lamb";
          HI.Kind = SymbolKind::Variable;
          HI.Definition = "auto lamb = [&bar](int T, bool B) -> bool {}";
-         HI.Type = std::string("class (lambda)");
+         HI.Type = "class (lambda)";
+         HI.ReturnType = "bool";
+         HI.Parameters = {
+             {std::string("int"), std::string("T"), llvm::None},
+             {std::string("bool"), std::string("B"), llvm::None},
+         };
          return HI;
        }},
       // Local variable in lambda




More information about the cfe-commits mailing list