Index: clang-tools-extra/clangd/Hover.cpp =================================================================== --- clang-tools-extra/clangd/Hover.cpp +++ clang-tools-extra/clangd/Hover.cpp @@ -628,7 +628,7 @@ return llvm::StringLiteral("expression"); } -// Generates hover info for evaluatable expressions. +// Generates hover info for `this` and evaluatable expressions. // FIXME: Support hover for literals (esp user-defined) llvm::Optional getHoverContents(const Expr *E, ParsedAST &AST) { // There's not much value in hovering over "42" and getting a hover card @@ -637,6 +637,41 @@ return llvm::None; HoverInfo HI; + // For `this` expr we currently generate hover with class declaration. + if (const CXXThisExpr *CTE = dyn_cast(E)) { + std::string Name; + llvm::raw_string_ostream OS(Name); + + const NamedDecl *ND = CTE->getType()->getPointeeType()->getAsTagDecl(); + const auto NS = getNamespaceScope(ND); + if (!NS.empty()) { + OS << NS << "::"; + } + OS << printName(AST.getASTContext(), *ND); + + // printName(...) will not output template parameters without specialization + // so fill in template params here + if (const TemplateDecl *TD = ND->getDescribedTemplate()) { + OS << "<"; + llvm::StringRef Sep = ""; + const auto PP = + printingPolicyForDecls(AST.getASTContext().getPrintingPolicy()); + for (const auto &P : + fetchTemplateParameters(TD->getTemplateParameters(), PP)) { + OS << Sep; + Sep = ", "; + if (P.Name) + OS << P.Name; + if (P.Default) + OS << " = " << P.Default; + } + OS << ">"; + } + OS << " *"; + + HI.Name = OS.str(); + return HI; + } // For expressions we currently print the type and the value, iff it is // evaluatable. if (auto Val = printExprValue(E, AST.getASTContext())) { Index: clang-tools-extra/clangd/unittests/HoverTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/HoverTests.cpp +++ clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -2019,6 +2019,41 @@ HI.NamespaceScope = ""; HI.Definition = "@interface MYObject\n@end"; }}, + { + R"cpp(// this expr + // comment + class Foo { + Foo* bar() { + return [[t^his]]; + } + }; + )cpp", + [](HoverInfo &HI) { HI.Name = "Foo *"; }}, + { + R"cpp(// this expr for template class + namespace ns { + template + class Foo { + Foo* bar() { + return [[t^his]]; + } + }; + } + )cpp", + [](HoverInfo &HI) { HI.Name = "ns::Foo *"; }}, + { + R"cpp(// this expr for specialization struct + namespace ns { + template struct Foo {}; + template + struct Foo { + Foo* bar() { + return [[thi^s]]; + } + }; + } + )cpp", + [](HoverInfo &HI) { HI.Name = "ns::Foo *"; }}, }; // Create a tiny index, so tests above can verify documentation is fetched.