hokein updated this revision to Diff 421856.
hokein added a comment.

add a unittest for template name.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123127/new/

https://reviews.llvm.org/D123127

Files:
  clang-tools-extra/clangd/DumpAST.cpp
  clang-tools-extra/clangd/SemanticHighlighting.cpp
  clang/include/clang/AST/PropertiesBase.td
  clang/include/clang/AST/TemplateName.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/ASTStructuralEquivalence.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/ODRHash.cpp
  clang/lib/AST/TemplateName.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/Type.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/AST/ast-dump-using-template.cpp
  clang/test/CXX/temp/temp.deduct.guide/p3.cpp
  clang/tools/libclang/CIndex.cpp
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/AST/CMakeLists.txt
  clang/unittests/AST/TemplateNameTest.cpp

Index: clang/unittests/AST/TemplateNameTest.cpp
===================================================================
--- /dev/null
+++ clang/unittests/AST/TemplateNameTest.cpp
@@ -0,0 +1,63 @@
+//===- unittests/AST/TemplateNameTest.cpp --- Tests for TemplateName ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTPrint.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace {
+using namespace ast_matchers;
+
+std::string printTemplateName(TemplateName TN, const PrintingPolicy &Policy,
+                              TemplateName::Qualified Qual) {
+  std::string Result;
+  llvm::raw_string_ostream Out(Result);
+  TN.print(Out, Policy, Qual);
+  return Out.str();
+}
+
+TEST(TemplateName, PrintUsingTemplate) {
+  std::string Code = R"cpp(
+    namespace std {
+      template <typename> struct vector {};
+    }
+    namespace absl { using std::vector; }
+
+    template<template <typename> class T> class X;
+
+    using absl::vector;
+    using A = X<vector>;
+  )cpp";
+  auto AST = tooling::buildASTFromCode(Code);
+  ASTContext &Ctx = AST->getASTContext();
+  // Match X in X<vector>.
+  auto Matcher = templateArgumentLoc().bind("id");
+
+  const auto *Template =
+      selectFirst<TemplateArgumentLoc>("id", match(Matcher, Ctx));
+  assert(Template);
+  TemplateName TN = Template->getArgument().getAsTemplate();
+  EXPECT_EQ(TN.getKind(), TemplateName::UsingTemplate);
+  EXPECT_EQ(TN.getAsUsingShadowDecl()->getTargetDecl(), TN.getAsTemplateDecl());
+
+  EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(),
+                              TemplateName::Qualified::Fully),
+            "std::vector");
+  EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(),
+                              TemplateName::Qualified::AsWritten),
+            "vector");
+  EXPECT_EQ(printTemplateName(TN, Ctx.getPrintingPolicy(),
+                              TemplateName::Qualified::None),
+            "vector");
+}
+
+} // namespace
+} // namespace clang
Index: clang/unittests/AST/CMakeLists.txt
===================================================================
--- clang/unittests/AST/CMakeLists.txt
+++ clang/unittests/AST/CMakeLists.txt
@@ -30,6 +30,7 @@
   SourceLocationTest.cpp
   StmtPrinterTest.cpp
   StructuralEquivalenceTest.cpp
+  TemplateNameTest.cpp
   TypePrinterTest.cpp
   )
 
Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -890,6 +890,18 @@
              functionDecl(hasDescendant(usingDecl(hasName("bar")))));
 }
 
+TEST_P(ImportDecl, ImportUsingTemplate) {
+  MatchVerifier<Decl> Verifier;
+  testImport("namespace ns { template <typename T> struct S {}; }"
+             "template <template <typename> class T> class X {};"
+             "void declToImport() {"
+             "using ns::S;  X<S> xi; }",
+             Lang_CXX11, "", Lang_CXX11, Verifier,
+             functionDecl(
+                 hasDescendant(varDecl(hasTypeLoc(templateSpecializationTypeLoc(
+                     hasAnyTemplateArgumentLoc(templateArgumentLoc())))))));
+}
+
 TEST_P(ImportDecl, ImportUsingEnumDecl) {
   MatchVerifier<Decl> Verifier;
   testImport("namespace foo { enum bar { baz, toto, quux }; }"
Index: clang/tools/libclang/CIndex.cpp
===================================================================
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -1442,6 +1442,7 @@
 bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
   switch (Name.getKind()) {
   case TemplateName::Template:
+  case TemplateName::UsingTemplate:
     return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU));
 
   case TemplateName::OverloadedTemplate:
Index: clang/test/CXX/temp/temp.deduct.guide/p3.cpp
===================================================================
--- clang/test/CXX/temp/temp.deduct.guide/p3.cpp
+++ clang/test/CXX/temp/temp.deduct.guide/p3.cpp
@@ -55,6 +55,9 @@
   }
   using N::NamedNS1;
   NamedNS1(int) -> NamedNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
+  // FIXME: remove the following bogus diagnostic
+  // expected-error@-2{{deduction guide is not written as a specialization of template 'NamedNS1'}}
+
   using namespace N;
   NamedNS2(int) -> NamedNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
   struct ClassMemberA {
Index: clang/test/AST/ast-dump-using-template.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/ast-dump-using-template.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++17 -ast-dump %s | FileCheck -strict-whitespace %s
+
+// Tests to verify we construct correct using template names.
+// TemplateNames are not dumped, so the sugar here isn't obvious. However
+// the "using" on the TemplateSpecializationTypes shows that the
+// UsingTemplateName is present.
+namespace ns {
+template<typename T> class S {
+ public:
+   S(T);
+};
+}
+using ns::S;
+
+// TemplateName in TemplateSpecializationType.
+template<typename T>
+using A = S<T>;
+// CHECK:      TypeAliasDecl
+// CHECK-NEXT: `-TemplateSpecializationType {{.*}} 'S<T>' dependent using S
+
+// TemplateName in TemplateArgument.
+template <template <typename> class T> class X {};
+using B = X<S>;
+// CHECK:      TypeAliasDecl
+// CHECK-NEXT: `-TemplateSpecializationType {{.*}} 'X<ns::S>' sugar X
+// CHECK-NEXT:   |-TemplateArgument using template S
+// CHECK-NEXT:     `-RecordType {{.*}} 'X<ns::S>'
+// CHECK-NEXT:       `-ClassTemplateSpecialization {{.*}} 'X'
+
+// TemplateName in DeducedTemplateSpecializationType.
+S DeducedTemplateSpecializationT(123);
+using C = decltype(DeducedTemplateSpecializationT);
+// CHECK:      DecltypeType {{.*}}
+// CHECK-NEXT:  |-DeclRefExpr {{.*}}
+// CHECK-NEXT:  `-DeducedTemplateSpecializationType {{.*}} 'ns::S<int>' sugar using
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -11,11 +11,13 @@
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TemplateName.h"
 #include "clang/AST/TypeVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/LangOptions.h"
@@ -223,6 +225,7 @@
     return TNK_Non_template;
 
   NamedDecl *D = nullptr;
+  UsingShadowDecl *FoundUsingShadow = dyn_cast<UsingShadowDecl>(*R.begin());
   if (R.isAmbiguous()) {
     // If we got an ambiguity involving a non-function template, treat this
     // as a template name, and pick an arbitrary template for error recovery.
@@ -233,6 +236,7 @@
           AnyFunctionTemplates = true;
         else {
           D = FoundTemplate;
+          FoundUsingShadow = dyn_cast<UsingShadowDecl>(FoundD);
           break;
         }
       }
@@ -283,10 +287,14 @@
 
     if (SS.isSet() && !SS.isInvalid()) {
       NestedNameSpecifier *Qualifier = SS.getScopeRep();
-      Template = Context.getQualifiedTemplateName(Qualifier,
-                                                  hasTemplateKeyword, TD);
+      // FIXME: store the using TemplateName in QualifiedTemplateName if
+      // the TD is referred via a using-declaration.
+      Template =
+          Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, TD);
     } else {
-      Template = TemplateName(TD);
+      Template =
+          FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
+      assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
     }
 
     if (isa<FunctionTemplateDecl>(TD)) {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -11023,6 +11023,8 @@
       TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
       bool TemplateMatches =
           Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
+      // FIXME: We should consider other template kinds (using, qualified),
+      // otherwise we will emit bogus diagnostics.
       if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches)
         AcceptableReturnType = true;
       else {
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -503,9 +503,11 @@
     FoundUsingShadow = nullptr;
   } else if (AllowDeducedTemplate) {
     if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
-      // FIXME: TemplateName should include FoundUsingShadow sugar.
-      T = Context.getDeducedTemplateSpecializationType(TemplateName(TD),
-                                                       QualType(), false);
+      assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
+      TemplateName Template =
+          FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
+      T = Context.getDeducedTemplateSpecializationType(Template, QualType(),
+                                                       false);
       // Don't wrap in a further UsingType.
       FoundUsingShadow = nullptr;
     }
@@ -1106,12 +1108,19 @@
       IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
       IsVarTemplate = isa<VarTemplateDecl>(TD);
 
+      UsingShadowDecl *FoundUsingShadow =
+          dyn_cast<UsingShadowDecl>(*Result.begin());
+
       if (SS.isNotEmpty())
         Template =
             Context.getQualifiedTemplateName(SS.getScopeRep(),
                                              /*TemplateKeyword=*/false, TD);
-      else
-        Template = TemplateName(TD);
+      else {
+        assert(!FoundUsingShadow ||
+               TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
+        Template = FoundUsingShadow ? TemplateName(FoundUsingShadow)
+                                    : TemplateName(TD);
+      }
     } else {
       // All results were non-template functions. This is a function template
       // name.
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -3686,7 +3686,8 @@
          "Use DependentTemplateSpecializationType for dependent template-name");
   assert((T.getKind() == TemplateName::Template ||
           T.getKind() == TemplateName::SubstTemplateTemplateParm ||
-          T.getKind() == TemplateName::SubstTemplateTemplateParmPack) &&
+          T.getKind() == TemplateName::SubstTemplateTemplateParmPack ||
+          T.getKind() == TemplateName::UsingTemplate) &&
          "Unexpected template name for TemplateSpecializationType");
 
   auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -900,12 +900,17 @@
 }
 
 void TextNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) {
+  if (TA.getAsTemplate().getKind() == TemplateName::UsingTemplate)
+    OS << " using";
   OS << " template ";
   TA.getAsTemplate().dump(OS);
 }
 
 void TextNodeDumper::VisitTemplateExpansionTemplateArgument(
     const TemplateArgument &TA) {
+  if (TA.getAsTemplateOrTemplatePattern().getKind() ==
+      TemplateName::UsingTemplate)
+    OS << " using";
   OS << " template expansion ";
   TA.getAsTemplateOrTemplatePattern().dump(OS);
 }
@@ -1575,10 +1580,18 @@
   }
 }
 
+void TextNodeDumper::VisitDeducedTemplateSpecializationType(
+    const DeducedTemplateSpecializationType *T) {
+  if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
+    OS << " using";
+}
+
 void TextNodeDumper::VisitTemplateSpecializationType(
     const TemplateSpecializationType *T) {
   if (T->isTypeAlias())
     OS << " alias";
+  if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
+    OS << " using";
   OS << " ";
   T->getTemplateName().dump(OS);
 }
Index: clang/lib/AST/TemplateName.cpp
===================================================================
--- clang/lib/AST/TemplateName.cpp
+++ clang/lib/AST/TemplateName.cpp
@@ -13,6 +13,7 @@
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DependenceFlags.h"
 #include "clang/AST/NestedNameSpecifier.h"
@@ -76,6 +77,7 @@
     : Storage(Storage) {}
 TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
 TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
+TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {}
 
 bool TemplateName::isNull() const { return Storage.isNull(); }
 
@@ -86,6 +88,8 @@
     return DependentTemplate;
   if (Storage.is<QualifiedTemplateName *>())
     return QualifiedTemplate;
+  if (Storage.is<UsingShadowDecl *>())
+    return UsingTemplate;
 
   UncommonTemplateNameStorage *uncommon
     = Storage.get<UncommonTemplateNameStorage*>();
@@ -108,6 +112,9 @@
   if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
     return sub->getReplacement().getAsTemplateDecl();
 
+  if (auto *USD = Storage.dyn_cast<UsingShadowDecl *>())
+    return cast<TemplateDecl>(USD->getTargetDecl());
+
   return nullptr;
 }
 
@@ -153,6 +160,10 @@
   return Storage.dyn_cast<DependentTemplateName *>();
 }
 
+UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
+  return Storage.dyn_cast<UsingShadowDecl *>();
+}
+
 TemplateName TemplateName::getNameToSubstitute() const {
   TemplateDecl *Decl = getAsTemplateDecl();
 
@@ -222,7 +233,10 @@
 
 void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
                          Qualified Qual) const {
-  if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
+  TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>();
+  if (getKind() == TemplateName::UsingTemplate)
+    Template = getAsTemplateDecl();
+  if (Template)
     if (Policy.CleanUglifiedParameters &&
         isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
       OS << Template->getIdentifier()->deuglifiedName();
@@ -262,6 +276,7 @@
   else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
     Assumed->getDeclName().print(OS, Policy);
   } else {
+    assert(getKind() == TemplateName::OverloadedTemplate);
     OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
     (*OTS->begin())->printName(OS);
   }
Index: clang/lib/AST/ODRHash.cpp
===================================================================
--- clang/lib/AST/ODRHash.cpp
+++ clang/lib/AST/ODRHash.cpp
@@ -150,6 +150,7 @@
   case TemplateName::DependentTemplate:
   case TemplateName::SubstTemplateTemplateParm:
   case TemplateName::SubstTemplateTemplateParmPack:
+  case TemplateName::UsingTemplate:
     break;
   }
 }
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -2207,6 +2207,7 @@
     TD = TN.getAsQualifiedTemplateName()->getTemplateDecl();
     goto HaveDecl;
 
+  case TemplateName::UsingTemplate:
   case TemplateName::Template:
     TD = TN.getAsTemplateDecl();
     goto HaveDecl;
@@ -2383,6 +2384,12 @@
       Out << "_SUBSTPACK_";
       break;
     }
+    case TemplateName::UsingTemplate: {
+      TemplateDecl *TD = TN.getAsTemplateDecl();
+      assert(TD && !isa<TemplateTemplateParmDecl>(TD));
+      mangleSourceNameWithAbiTags(TD);
+      break;
+    }
     }
 
     // Note: we don't pass in the template name here. We are mangling the
Index: clang/lib/AST/ASTStructuralEquivalence.cpp
===================================================================
--- clang/lib/AST/ASTStructuralEquivalence.cpp
+++ clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -517,6 +517,7 @@
    case TemplateName::Template:
    case TemplateName::QualifiedTemplate:
    case TemplateName::SubstTemplateTemplateParm:
+   case TemplateName::UsingTemplate:
      // It is sufficient to check value of getAsTemplateDecl.
      break;
 
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -9186,6 +9186,12 @@
     return ToContext.getSubstTemplateTemplateParmPack(
         cast<TemplateTemplateParmDecl>(*ParamOrErr), *ArgPackOrErr);
   }
+  case TemplateName::UsingTemplate: {
+    auto UsingOrError = Import(From.getAsUsingShadowDecl());
+    if (!UsingOrError)
+      return UsingOrError.takeError();
+    return TemplateName(cast<UsingShadowDecl>(*UsingOrError));
+  }
   }
 
   llvm_unreachable("Invalid template name kind");
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -6125,6 +6125,9 @@
     return DeclarationNameInfo(subst->getParameterPack()->getDeclName(),
                                NameLoc);
   }
+  case TemplateName::UsingTemplate:
+    return DeclarationNameInfo(Name.getAsUsingShadowDecl()->getDeclName(),
+                               NameLoc);
   }
 
   llvm_unreachable("bad template name kind!");
@@ -6133,6 +6136,7 @@
 TemplateName
 ASTContext::getCanonicalTemplateName(const TemplateName &Name) const {
   switch (Name.getKind()) {
+  case TemplateName::UsingTemplate:
   case TemplateName::QualifiedTemplate:
   case TemplateName::Template: {
     TemplateDecl *Template = Name.getAsTemplateDecl();
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -317,6 +317,8 @@
   void VisitTagType(const TagType *T);
   void VisitTemplateTypeParmType(const TemplateTypeParmType *T);
   void VisitAutoType(const AutoType *T);
+  void VisitDeducedTemplateSpecializationType(
+      const DeducedTemplateSpecializationType *T);
   void VisitTemplateSpecializationType(const TemplateSpecializationType *T);
   void VisitInjectedClassNameType(const InjectedClassNameType *T);
   void VisitObjCInterfaceType(const ObjCInterfaceType *T);
Index: clang/include/clang/AST/TemplateName.h
===================================================================
--- clang/include/clang/AST/TemplateName.h
+++ clang/include/clang/AST/TemplateName.h
@@ -39,6 +39,7 @@
 class TemplateArgument;
 class TemplateDecl;
 class TemplateTemplateParmDecl;
+class UsingShadowDecl;
 
 /// Implementation class used to describe either a set of overloaded
 /// template names or an already-substituted template template parameter pack.
@@ -190,7 +191,8 @@
 class TemplateName {
   using StorageType =
       llvm::PointerUnion<TemplateDecl *, UncommonTemplateNameStorage *,
-                         QualifiedTemplateName *, DependentTemplateName *>;
+                         QualifiedTemplateName *, DependentTemplateName *,
+                         UsingShadowDecl *>;
 
   StorageType Storage;
 
@@ -224,7 +226,11 @@
     /// A template template parameter pack that has been substituted for
     /// a template template argument pack, but has not yet been expanded into
     /// individual arguments.
-    SubstTemplateTemplateParmPack
+    SubstTemplateTemplateParmPack,
+
+    /// A template name that refers to a template declaration found through a
+    /// specific using shadow declaration.
+    UsingTemplate,
   };
 
   TemplateName() = default;
@@ -235,6 +241,7 @@
   explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage);
   explicit TemplateName(QualifiedTemplateName *Qual);
   explicit TemplateName(DependentTemplateName *Dep);
+  explicit TemplateName(UsingShadowDecl *Using);
 
   /// Determine whether this template name is NULL.
   bool isNull() const;
@@ -287,6 +294,13 @@
   /// structure, if any.
   DependentTemplateName *getAsDependentTemplateName() const;
 
+  /// Retrieve the using shadow declaration through which the underlying
+  /// template declaration is introduced.
+  ///
+  /// The underlying template declaration is not stored in the template name, it
+  /// can be retrieved via the using shadow declaration.
+  UsingShadowDecl *getAsUsingShadowDecl() const;
+
   TemplateName getUnderlying() const;
 
   /// Get the template name to substitute when this template name is used as a
Index: clang/include/clang/AST/PropertiesBase.td
===================================================================
--- clang/include/clang/AST/PropertiesBase.td
+++ clang/include/clang/AST/PropertiesBase.td
@@ -620,6 +620,16 @@
     return TemplateName(declaration);
   }]>;
 }
+
+let Class = PropertyTypeCase<TemplateName, "UsingTemplate"> in {
+  def : Property<"foundDecl", UsingShadowDeclRef> {
+    let Read = [{ node.getAsUsingShadowDecl() }];
+  }
+  def : Creator<[{
+    return TemplateName(foundDecl);
+  }]>;
+}
+
 let Class = PropertyTypeCase<TemplateName, "OverloadedTemplate"> in {
   def : Property<"overloads", Array<NamedDeclRef>> {
     let Read = [{ node.getAsOverloadedTemplate()->decls() }];
Index: clang-tools-extra/clangd/SemanticHighlighting.cpp
===================================================================
--- clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -762,6 +762,7 @@
     case TemplateName::QualifiedTemplate:
     case TemplateName::SubstTemplateTemplateParm:
     case TemplateName::SubstTemplateTemplateParmPack:
+    case TemplateName::UsingTemplate:
       // Names that could be resolved to a TemplateDecl are handled elsewhere.
       break;
     }
Index: clang-tools-extra/clangd/DumpAST.cpp
===================================================================
--- clang-tools-extra/clangd/DumpAST.cpp
+++ clang-tools-extra/clangd/DumpAST.cpp
@@ -184,6 +184,7 @@
       TEMPLATE_KIND(DependentTemplate);
       TEMPLATE_KIND(SubstTemplateTemplateParm);
       TEMPLATE_KIND(SubstTemplateTemplateParmPack);
+      TEMPLATE_KIND(UsingTemplate);
 #undef TEMPLATE_KIND
     }
     llvm_unreachable("Unhandled NameKind enum");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to