Index: clang-tools-extra/clangd/Hover.cpp =================================================================== --- clang-tools-extra/clangd/Hover.cpp +++ clang-tools-extra/clangd/Hover.cpp @@ -628,15 +628,22 @@ 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) { +llvm::Optional getHoverContents(const Expr *E, ParsedAST &AST, + const SymbolIndex *Index) { // There's not much value in hovering over "42" and getting a hover card // saying "42 is an int", similar for other literals. if (isLiteral(E)) return llvm::None; HoverInfo HI; + // For `this` expr we currently generate hover with class declaration. + if (const CXXThisExpr *CTE = dyn_cast(E)) { + const NamedDecl *D = CTE->getType()->getPointeeType()->getAsTagDecl(); + HI = getHoverContents(D, Index); + return HI; + } // For expressions we currently print the type and the value, iff it is // evaluatable. if (auto Val = printExprValue(E, AST.getASTContext())) { @@ -861,7 +868,7 @@ HI->Value = printExprValue(N, AST.getASTContext()); maybeAddCalleeArgInfo(N, *HI, AST.getASTContext().getPrintingPolicy()); } else if (const Expr *E = N->ASTNode.get()) { - HI = getHoverContents(E, AST); + HI = getHoverContents(E, AST, Index); } // FIXME: support hovers for other nodes? // - built-in types 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,61 @@ HI.NamespaceScope = ""; HI.Definition = "@interface MYObject\n@end"; }}, + { + R"cpp(// this expr + namespace ns { + // comment + class Foo { + Foo* bar() { + return [[t^his]]; + } + }; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "Foo"; + HI.Kind = index::SymbolKind::Class; + HI.NamespaceScope = "ns::"; + HI.Definition = "class Foo {}"; + HI.Documentation = "comment"; + }}, + { + R"cpp(// this expr for template class + namespace ns { + template + class Foo { + Foo* bar() { + return [[t^his]]; + } + }; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "Foo"; + HI.Kind = index::SymbolKind::Class; + HI.NamespaceScope = "ns::"; + HI.Definition = "template class Foo {}"; + HI.TemplateParameters = { + {std::string("typename"), std::string("T"), llvm::None}}; + }}, + { + 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 = "Foo"; + HI.Kind = index::SymbolKind::Struct; + HI.NamespaceScope = "ns::"; + HI.Definition = "template <> struct Foo {}"; + }}, }; // Create a tiny index, so tests above can verify documentation is fetched.