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" @@ -652,8 +654,28 @@ } } + auto ToFunctionDecl = [](const Decl *D) -> const FunctionDecl * { + // Extract lambda from variables. + if (const VarDecl *VD = llvm::dyn_cast(D)) { + // It might be declared by a decltype. + if (const DecltypeType *DT = + llvm::dyn_cast(VD->getType().getTypePtr())) + if (!DT->getUnderlyingType().isNull()) + if (const auto *CD = DT->getUnderlyingType()->getAsCXXRecordDecl()) + return CD->getLambdaCallOperator(); + + // Or with an initializer. + if (const Expr *E = VD->getInit()) + if (const LambdaExpr *LE = llvm::dyn_cast(E)) + return LE->getCallOperator(); + } + + // Non-lambda functions. + return D->getAsFunction(); + }; + // Fill in types and params. - if (const FunctionDecl *FD = D->getAsFunction()) { + if (const FunctionDecl *FD = ToFunctionDecl(D)) { HI.ReturnType.emplace(); llvm::raw_string_ostream OS(*HI.ReturnType); FD->getReturnType().print(OS, Policy); @@ -692,8 +714,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,27 @@ {std::string("bool"), std::string("T"), std::string("false")}, }; }}, + // 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 +801,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