diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -18,7 +18,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" @@ -619,6 +621,21 @@ CharSourceRange::getCharRange(Loc, End)); } +static const FunctionDecl *getUnderlyingFunction(const Decl *D) { + // Extract lambda from variables. + if (const VarDecl *VD = llvm::dyn_cast(D)) { + auto QT = VD->getType(); + 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; @@ -653,13 +670,15 @@ } // 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); + if (llvm::isa(D)) + TypeOS << " "; FD->getReturnType().print(TypeOS, Policy); TypeOS << '('; @@ -692,8 +711,6 @@ TypeOS << ')'; // FIXME: handle variadics. } else if (const auto *VD = dyn_cast(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); diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/ScopedPrinter.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include namespace clang { namespace clangd { @@ -765,6 +766,70 @@ {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 = " bool(int, bool)"; + 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 = " bool(int, bool)"; + 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 = " bool(int, bool)"; + 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 @@ 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 = " bool(int, bool)"; + 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