From a31a61dafeaa9110687110fc127ea6f7c91dd3e6 Mon Sep 17 00:00:00 2001 From: Kadir Cetinkaya Date: Fri, 24 Jan 2020 13:04:00 +0100 Subject: [PATCH] [clangd][Hover] Handle uninstantiated templates Summary: Fixes https://github.com/clangd/clangd/issues/263 Reviewers: hokein, sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73344 --- clang-tools-extra/clangd/Hover.cpp | 27 +++++++++++++++-------- clang-tools-extra/clangd/unittests/HoverTests.cpp | 19 ++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 26b6cf4..834c9d0 100644 --- 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 @@ const FunctionDecl *getUnderlyingFunction(const Decl *D) { // 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 index bb14ede..758c642 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -554,6 +554,25 @@ class Foo {})cpp"; 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); -- 2.7.4