Index: clang-tools-extra/trunk/clangd/XRefs.cpp =================================================================== --- clang-tools-extra/trunk/clangd/XRefs.cpp +++ clang-tools-extra/trunk/clangd/XRefs.cpp @@ -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 @@ 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(); + 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 @@ } // 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 @@ 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(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(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); Index: clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/XRefsTests.cpp +++ clang-tools-extra/trunk/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 { @@ -588,7 +589,7 @@ 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 @@ 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 @@ 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 class"), @@ -759,12 +760,76 @@ HI.Kind = SymbolKind::Function; HI.Definition = "Foo foo(int, bool T = false)"; HI.ReturnType = "Foo"; - HI.Type = "Foo(int, bool)"; + HI.Type = "Foo (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 @@ 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