diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -26,6 +26,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" +#include "clang/Basic/Specifiers.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" @@ -205,15 +206,23 @@ // Returns the decl that should be used for querying comments, either from index // or AST. const NamedDecl *getDeclForComment(const NamedDecl *D) { - if (auto *CTSD = llvm::dyn_cast(D)) - if (!CTSD->isExplicitInstantiationOrSpecialization()) - return CTSD->getTemplateInstantiationPattern(); - if (auto *VTSD = llvm::dyn_cast(D)) - if (!VTSD->isExplicitInstantiationOrSpecialization()) - return VTSD->getTemplateInstantiationPattern(); - if (auto *FD = D->getAsFunction()) - if (FD->isTemplateInstantiation()) - return FD->getTemplateInstantiationPattern(); + if (const auto *TSD = llvm::dyn_cast(D)) { + // Template may not be instantiated e.g. if the type didn't need to be + // complete; fallback to primary template. + if (TSD->getTemplateSpecializationKind() == TSK_Undeclared) + return TSD->getSpecializedTemplate(); + if (const auto *TIP = TSD->getTemplateInstantiationPattern()) + return TIP; + } + if (const auto *TSD = llvm::dyn_cast(D)) { + if (TSD->getTemplateSpecializationKind() == TSK_Undeclared) + return TSD->getSpecializedTemplate(); + if (const auto *TIP = TSD->getTemplateInstantiationPattern()) + return TIP; + } + if (const auto *FD = D->getAsFunction()) + if (const auto *TIP = FD->getTemplateInstantiationPattern()) + return TIP; return D; } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -554,6 +554,25 @@ HI.Name = "Foo"; HI.Kind = index::SymbolKind::Class; }}, + {// Falls back to primary template, when the type is not instantiated. + R"cpp( + // comment from primary + template class Foo {}; + // comment from specialization + template class Foo {}; + void foo() { + [[Fo^o]] *x = nullptr; + } + )cpp", + [](HoverInfo &HI) { + HI.Name = "Foo"; + HI.Kind = index::SymbolKind::Class; + HI.NamespaceScope = ""; + HI.Definition = "template <> class Foo"; + // FIXME: Maybe force instantiation to make use of real template + // pattern. + HI.Documentation = "comment from primary"; + }}, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Code);