Unverified Commit a31a61da authored by Kadir Cetinkaya's avatar Kadir Cetinkaya
Browse files

[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
parent f4871ead
Loading
Loading
Loading
Loading
+18 −9
Original line number Diff line number Diff line
@@ -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<ClassTemplateSpecializationDecl>(D))
    if (!CTSD->isExplicitInstantiationOrSpecialization())
      return CTSD->getTemplateInstantiationPattern();
  if (auto *VTSD = llvm::dyn_cast<VarTemplateSpecializationDecl>(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<ClassTemplateSpecializationDecl>(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<VarTemplateSpecializationDecl>(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;
}

+19 −0
Original line number Diff line number Diff line
@@ -554,6 +554,25 @@ class Foo {})cpp";
            HI.Name = "Foo<X>";
            HI.Kind = index::SymbolKind::Class;
          }},
      {// Falls back to primary template, when the type is not instantiated.
       R"cpp(
          // comment from primary
          template <typename T> class Foo {};
          // comment from specialization
          template <typename T> class Foo<T*> {};
          void foo() {
            [[Fo^o]]<int*> *x = nullptr;
          }
          )cpp",
       [](HoverInfo &HI) {
         HI.Name = "Foo<int *>";
         HI.Kind = index::SymbolKind::Class;
         HI.NamespaceScope = "";
         HI.Definition = "template <> class Foo<int *>";
         // 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);