https://github.com/daniel-grumberg created 
https://github.com/llvm/llvm-project/pull/91958

Previously we only generated declaration fragments for template type 
parameters/arguments, this adds supports for most other possible template 
parameters/arguments.

rdar://127732598

>From d86e4256da57451a08d580b8eecd5525bd1642c6 Mon Sep 17 00:00:00 2001
From: Daniel Grumberg <dgrumb...@apple.com>
Date: Wed, 8 May 2024 12:22:47 +0100
Subject: [PATCH] [clang][ExtractAPI] Correctly generate declaration fragments
 for non-type template parameters.

Previously we only generated declaration fragments for template type
paramters/arguments, this adds supports for most other possible template
parameters/arguments.

rdar://127732598
---
 clang/lib/ExtractAPI/DeclarationFragments.cpp | 226 ++++++++++---
 clang/test/ExtractAPI/class_template.cpp      |   2 +-
 .../class_template_param_inheritance.cpp      |   2 +-
 .../class_template_partial_spec.cpp           |   4 +-
 clang/test/ExtractAPI/class_template_spec.cpp |   4 +-
 clang/test/ExtractAPI/concept.cpp             |   2 +-
 clang/test/ExtractAPI/field_template.cpp      |   2 +-
 .../test/ExtractAPI/global_func_template.cpp  |   4 +-
 .../ExtractAPI/global_func_template_spec.cpp  |   4 +-
 clang/test/ExtractAPI/global_var_template.cpp |   2 +-
 .../global_var_template_partial_spec.cpp      |   4 +-
 .../ExtractAPI/global_var_template_spec.cpp   |   4 +-
 clang/test/ExtractAPI/method_template.cpp     |   2 +-
 .../test/ExtractAPI/method_template_spec.cpp  |   4 +-
 clang/test/ExtractAPI/non_type_template.cpp   | 313 ++++++++++++++++++
 15 files changed, 522 insertions(+), 57 deletions(-)
 create mode 100644 clang/test/ExtractAPI/non_type_template.cpp

diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp 
b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 9bf7950888dbb..98b9343924a83 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -12,13 +12,19 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/AST/ASTFwd.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
 #include "clang/Index/USRGeneration.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
 
 using namespace clang::extractapi;
 using namespace llvm;
@@ -386,6 +392,25 @@ DeclarationFragments 
DeclarationFragmentsBuilder::getFragmentsForType(
         getFragmentsForType(AT->getElementType(), Context, After));
   }
 
+  if (const TemplateSpecializationType *TemplSpecTy =
+          dyn_cast<TemplateSpecializationType>(T)) {
+    const auto TemplName = TemplSpecTy->getTemplateName();
+    std::string Str;
+    raw_string_ostream Stream(Str);
+    TemplName.print(Stream, Context.getPrintingPolicy(),
+                    TemplateName::Qualified::AsWritten);
+    SmallString<64> USR("");
+    if (const auto *TemplDecl = TemplName.getAsTemplateDecl())
+      index::generateUSRForDecl(TemplDecl, USR);
+
+    return Fragments
+        .append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR)
+        .append("<", DeclarationFragments::FragmentKind::Text)
+        .append(getFragmentsForTemplateArguments(
+            TemplSpecTy->template_arguments(), Context, std::nullopt))
+        .append(">", DeclarationFragments::FragmentKind::Text);
+  }
+
   // Everything we care about has been handled now, reduce to the canonical
   // unqualified base type.
   QualType Base = T->getCanonicalTypeUnqualified();
@@ -650,7 +675,6 @@ DeclarationFragments 
DeclarationFragmentsBuilder::getFragmentsForBlock(
 DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) 
{
   DeclarationFragments Fragments;
-  // FIXME: Handle template specialization
   switch (Func->getStorageClass()) {
   case SC_None:
   case SC_PrivateExtern:
@@ -952,27 +976,84 @@ 
DeclarationFragmentsBuilder::getFragmentsForTemplateParameters(
       Fragments.append(",", DeclarationFragments::FragmentKind::Text)
           .appendSpace();
 
-    const auto *TemplateParam =
-        dyn_cast<TemplateTypeParmDecl>(ParameterArray[i]);
-    if (!TemplateParam)
-      continue;
-    if (TemplateParam->hasTypeConstraint())
-      Fragments.append(TemplateParam->getTypeConstraint()
-                           ->getNamedConcept()
-                           ->getName()
-                           .str(),
-                       DeclarationFragments::FragmentKind::TypeIdentifier);
-    else if (TemplateParam->wasDeclaredWithTypename())
-      Fragments.append("typename", 
DeclarationFragments::FragmentKind::Keyword);
-    else
-      Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
-
-    if (TemplateParam->isParameterPack())
-      Fragments.append("...", DeclarationFragments::FragmentKind::Text);
-
-    Fragments.appendSpace().append(
-        TemplateParam->getName(),
-        DeclarationFragments::FragmentKind::GenericParameter);
+    if (const auto *TemplateParam =
+            dyn_cast<TemplateTypeParmDecl>(ParameterArray[i])) {
+      if (TemplateParam->hasTypeConstraint())
+        Fragments.append(TemplateParam->getTypeConstraint()
+                             ->getNamedConcept()
+                             ->getName()
+                             .str(),
+                         DeclarationFragments::FragmentKind::TypeIdentifier);
+      else if (TemplateParam->wasDeclaredWithTypename())
+        Fragments.append("typename",
+                         DeclarationFragments::FragmentKind::Keyword);
+      else
+        Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
+
+      if (TemplateParam->isParameterPack())
+        Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+      if (!TemplateParam->getName().empty())
+        Fragments.appendSpace().append(
+            TemplateParam->getName(),
+            DeclarationFragments::FragmentKind::GenericParameter);
+
+      if (TemplateParam->hasDefaultArgument()) {
+        DeclarationFragments After;
+        Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+            .append(getFragmentsForType(TemplateParam->getDefaultArgument(),
+                                        TemplateParam->getASTContext(), 
After));
+        Fragments.append(std::move(After));
+      }
+    } else if (const auto *NTP =
+                   dyn_cast<NonTypeTemplateParmDecl>(ParameterArray[i])) {
+      DeclarationFragments After;
+      const auto TyFragments =
+          getFragmentsForType(NTP->getType(), NTP->getASTContext(), After);
+      Fragments.append(std::move(TyFragments)).append(std::move(After));
+
+      if (NTP->isParameterPack())
+        Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+      if (!NTP->getName().empty())
+        Fragments.appendSpace().append(
+            NTP->getName(),
+            DeclarationFragments::FragmentKind::GenericParameter);
+
+      if (NTP->hasDefaultArgument()) {
+        SmallString<8> ExprStr;
+        raw_svector_ostream Output(ExprStr);
+        NTP->getDefaultArgument()->printPretty(
+            Output, nullptr, NTP->getASTContext().getPrintingPolicy());
+        Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+            .append(ExprStr, DeclarationFragments::FragmentKind::Text);
+      }
+    } else if (const auto *TTP =
+                   dyn_cast<TemplateTemplateParmDecl>(ParameterArray[i])) {
+      Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
+          .appendSpace()
+          .append("<", DeclarationFragments::FragmentKind::Text)
+          .append(getFragmentsForTemplateParameters(
+              TTP->getTemplateParameters()->asArray()))
+          .append(">", DeclarationFragments::FragmentKind::Text)
+          .appendSpace()
+          .append(TTP->wasDeclaredWithTypename() ? "typename" : "class",
+                  DeclarationFragments::FragmentKind::Keyword);
+
+      if (TTP->isParameterPack())
+        Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+
+      if (!TTP->getName().empty())
+        Fragments.appendSpace().append(
+            TTP->getName(),
+            DeclarationFragments::FragmentKind::GenericParameter);
+      if (TTP->hasDefaultArgument()) {
+        const auto Default = TTP->getDefaultArgument();
+        Fragments.append(" = ", DeclarationFragments::FragmentKind::Text)
+            .append(getFragmentsForTemplateArguments(
+                {Default.getArgument()}, TTP->getASTContext(), {Default}));
+      }
+    }
   }
   return Fragments;
 }
@@ -993,23 +1074,85 @@ 
DeclarationFragmentsBuilder::getFragmentsForTemplateArguments(
       Fragments.append(",", DeclarationFragments::FragmentKind::Text)
           .appendSpace();
 
-    std::string Type = TemplateArguments[i].getAsType().getAsString();
-    DeclarationFragments After;
-    DeclarationFragments ArgumentFragment =
-        getFragmentsForType(TemplateArguments[i].getAsType(), Context, After);
-
-    if (StringRef(ArgumentFragment.begin()->Spelling)
-            .starts_with("type-parameter")) {
-      std::string ProperArgName = TemplateArgumentLocs.value()[i]
-                                      .getTypeSourceInfo()
-                                      ->getType()
-                                      .getAsString();
-      ArgumentFragment.begin()->Spelling.swap(ProperArgName);
+    const auto &CTA = TemplateArguments[i];
+    switch (CTA.getKind()) {
+    case TemplateArgument::Type: {
+      DeclarationFragments After;
+      DeclarationFragments ArgumentFragment =
+          getFragmentsForType(CTA.getAsType(), Context, After);
+
+      if (StringRef(ArgumentFragment.begin()->Spelling)
+              .starts_with("type-parameter")) {
+        std::string ProperArgName = TemplateArgumentLocs.value()[i]
+                                        .getTypeSourceInfo()
+                                        ->getType()
+                                        .getAsString();
+        ArgumentFragment.begin()->Spelling.swap(ProperArgName);
+      }
+      Fragments.append(std::move(ArgumentFragment));
+      break;
     }
-    Fragments.append(std::move(ArgumentFragment));
+    case TemplateArgument::Declaration: {
+      const auto *VD = CTA.getAsDecl();
+      SmallString<128> USR;
+      index::generateUSRForDecl(VD, USR);
+      Fragments.append(VD->getNameAsString(),
+                       DeclarationFragments::FragmentKind::Identifier, USR);
+      break;
+    }
+    case TemplateArgument::NullPtr:
+      Fragments.append("nullptr", DeclarationFragments::FragmentKind::Keyword);
+      break;
 
-    if (TemplateArguments[i].isPackExpansion())
-      Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+    case TemplateArgument::Integral: {
+      SmallString<4> Str;
+      CTA.getAsIntegral().toString(Str);
+      Fragments.append(Str, DeclarationFragments::FragmentKind::Text);
+      break;
+    }
+
+    case TemplateArgument::StructuralValue: {
+      const auto SVTy = CTA.getStructuralValueType();
+      Fragments.append(CTA.getAsStructuralValue().getAsString(Context, SVTy),
+                       DeclarationFragments::FragmentKind::Text);
+      break;
+    }
+
+    case TemplateArgument::TemplateExpansion:
+    case TemplateArgument::Template: {
+      std::string Str;
+      raw_string_ostream Stream(Str);
+      CTA.getAsTemplate().print(Stream, Context.getPrintingPolicy());
+      SmallString<64> USR("");
+      if (const auto *TemplDecl =
+              CTA.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+        index::generateUSRForDecl(TemplDecl, USR);
+      Fragments.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier,
+                       USR);
+      if (CTA.getKind() == TemplateArgument::TemplateExpansion)
+        Fragments.append("...", DeclarationFragments::FragmentKind::Text);
+      break;
+    }
+
+    case TemplateArgument::Pack:
+      Fragments.append("<", DeclarationFragments::FragmentKind::Text)
+          .append(getFragmentsForTemplateArguments(CTA.pack_elements(), 
Context,
+                                                   {}))
+          .append(">", DeclarationFragments::FragmentKind::Text);
+      break;
+
+    case TemplateArgument::Expression: {
+      SmallString<8> ExprStr;
+      raw_svector_ostream Output(ExprStr);
+      CTA.getAsExpr()->printPretty(Output, nullptr,
+                                   Context.getPrintingPolicy());
+      Fragments.append(ExprStr, DeclarationFragments::FragmentKind::Text);
+      break;
+    }
+
+    case TemplateArgument::Null:
+      break;
+    }
   }
   return Fragments;
 }
@@ -1019,10 +1162,12 @@ DeclarationFragments 
DeclarationFragmentsBuilder::getFragmentsForConcept(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       .append(getFragmentsForTemplateParameters(
           Concept->getTemplateParameters()->asArray()))
       .append("> ", DeclarationFragments::FragmentKind::Text)
+      .appendSpace()
       .append("concept", DeclarationFragments::FragmentKind::Keyword)
       .appendSpace()
       .append(Concept->getName().str(),
@@ -1035,6 +1180,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
     const RedeclarableTemplateDecl *RedeclarableTemplate) {
   DeclarationFragments Fragments;
   Fragments.append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       .append(getFragmentsForTemplateParameters(
           RedeclarableTemplate->getTemplateParameters()->asArray()))
@@ -1057,6 +1203,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       .append(">", DeclarationFragments::FragmentKind::Text)
       .appendSpace()
@@ -1077,6 +1224,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       .append(getFragmentsForTemplateParameters(
           Decl->getTemplateParameters()->asArray()))
@@ -1099,6 +1247,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       .append(">", DeclarationFragments::FragmentKind::Text)
       .appendSpace()
@@ -1118,6 +1267,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       // Partial specs may have new params.
       .append(getFragmentsForTemplateParameters(
@@ -1140,6 +1290,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<", DeclarationFragments::FragmentKind::Text)
       // Partial specs may have new params.
       .append(getFragmentsForTemplateParameters(
@@ -1156,6 +1307,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization(
   DeclarationFragments Fragments;
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
+      .appendSpace()
       .append("<>", DeclarationFragments::FragmentKind::Text)
       .appendSpace()
       .append(DeclarationFragmentsBuilder::getFragmentsForFunction(Decl));
diff --git a/clang/test/ExtractAPI/class_template.cpp 
b/clang/test/ExtractAPI/class_template.cpp
index 4f2670d7b6997..203d47394dd60 100644
--- a/clang/test/ExtractAPI/class_template.cpp
+++ b/clang/test/ExtractAPI/class_template.cpp
@@ -51,7 +51,7 @@ template<typename T> class Foo {};
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/class_template_param_inheritance.cpp 
b/clang/test/ExtractAPI/class_template_param_inheritance.cpp
index 3d7b09f93ed6d..53b331e0b460b 100644
--- a/clang/test/ExtractAPI/class_template_param_inheritance.cpp
+++ b/clang/test/ExtractAPI/class_template_param_inheritance.cpp
@@ -58,7 +58,7 @@ template<typename T> class Foo : public T {};
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/class_template_partial_spec.cpp 
b/clang/test/ExtractAPI/class_template_partial_spec.cpp
index c8d9cc78d41c5..7d244f49c7359 100644
--- a/clang/test/ExtractAPI/class_template_partial_spec.cpp
+++ b/clang/test/ExtractAPI/class_template_partial_spec.cpp
@@ -53,7 +53,7 @@ template<typename Z> class Foo<Z, int> {};
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -161,7 +161,7 @@ template<typename Z> class Foo<Z, int> {};
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/class_template_spec.cpp 
b/clang/test/ExtractAPI/class_template_spec.cpp
index 06a95314dc4aa..9dbd887510c70 100644
--- a/clang/test/ExtractAPI/class_template_spec.cpp
+++ b/clang/test/ExtractAPI/class_template_spec.cpp
@@ -53,7 +53,7 @@ template<> class Foo<int> {};
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -140,7 +140,7 @@ template<> class Foo<int> {};
         },
         {
           "kind": "text",
-          "spelling": "<> "
+          "spelling": " <> "
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/concept.cpp 
b/clang/test/ExtractAPI/concept.cpp
index 443eac2971f0e..4396a39a63ef6 100644
--- a/clang/test/ExtractAPI/concept.cpp
+++ b/clang/test/ExtractAPI/concept.cpp
@@ -51,7 +51,7 @@ template<typename T> concept Foo = true;
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/field_template.cpp 
b/clang/test/ExtractAPI/field_template.cpp
index 2058ed008cfe4..973a9de5c9986 100644
--- a/clang/test/ExtractAPI/field_template.cpp
+++ b/clang/test/ExtractAPI/field_template.cpp
@@ -114,7 +114,7 @@ class Foo {
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_func_template.cpp 
b/clang/test/ExtractAPI/global_func_template.cpp
index f43a618ec0c36..044757c316d58 100644
--- a/clang/test/ExtractAPI/global_func_template.cpp
+++ b/clang/test/ExtractAPI/global_func_template.cpp
@@ -52,7 +52,7 @@ template<typename T> T Fizz(int Buzz);
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -186,7 +186,7 @@ template<typename T> T Fizz(int Buzz);
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_func_template_spec.cpp 
b/clang/test/ExtractAPI/global_func_template_spec.cpp
index fe046e9c3b9da..b88063aacfedc 100644
--- a/clang/test/ExtractAPI/global_func_template_spec.cpp
+++ b/clang/test/ExtractAPI/global_func_template_spec.cpp
@@ -52,7 +52,7 @@ template<> void Foo<int>(int Bar);
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -186,7 +186,7 @@ template<> void Foo<int>(int Bar);
         },
         {
           "kind": "text",
-          "spelling": "<> "
+          "spelling": " <> "
         },
         {
           "kind": "typeIdentifier",
diff --git a/clang/test/ExtractAPI/global_var_template.cpp 
b/clang/test/ExtractAPI/global_var_template.cpp
index 94f3713cd3d31..5c9194141332b 100644
--- a/clang/test/ExtractAPI/global_var_template.cpp
+++ b/clang/test/ExtractAPI/global_var_template.cpp
@@ -50,7 +50,7 @@ template<typename T> T Foo = T(3.14);
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp 
b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp
index 91084f258878e..ffb1557fd7580 100644
--- a/clang/test/ExtractAPI/global_var_template_partial_spec.cpp
+++ b/clang/test/ExtractAPI/global_var_template_partial_spec.cpp
@@ -52,7 +52,7 @@ template<typename Z> int Foo<int, Z> = 0;
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -161,7 +161,7 @@ template<typename Z> int Foo<int, Z> = 0;
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/global_var_template_spec.cpp 
b/clang/test/ExtractAPI/global_var_template_spec.cpp
index ff4d8d17aecbe..e465da97db1f2 100644
--- a/clang/test/ExtractAPI/global_var_template_spec.cpp
+++ b/clang/test/ExtractAPI/global_var_template_spec.cpp
@@ -52,7 +52,7 @@ template<> int Foo<int>;
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -140,7 +140,7 @@ template<> int Foo<int>;
         },
         {
           "kind": "text",
-          "spelling": "<> "
+          "spelling": " <> "
         },
         {
           "kind": "typeIdentifier",
diff --git a/clang/test/ExtractAPI/method_template.cpp 
b/clang/test/ExtractAPI/method_template.cpp
index 714f9cac26c20..bf91a208c5488 100644
--- a/clang/test/ExtractAPI/method_template.cpp
+++ b/clang/test/ExtractAPI/method_template.cpp
@@ -114,7 +114,7 @@ class Foo {
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
diff --git a/clang/test/ExtractAPI/method_template_spec.cpp 
b/clang/test/ExtractAPI/method_template_spec.cpp
index 8eaffdefd827a..978dbe1b6c1d6 100644
--- a/clang/test/ExtractAPI/method_template_spec.cpp
+++ b/clang/test/ExtractAPI/method_template_spec.cpp
@@ -122,7 +122,7 @@ class Foo {
         },
         {
           "kind": "text",
-          "spelling": "<"
+          "spelling": " <"
         },
         {
           "kind": "keyword",
@@ -257,7 +257,7 @@ class Foo {
         },
         {
           "kind": "text",
-          "spelling": "<> "
+          "spelling": " <> "
         },
         {
           "kind": "typeIdentifier",
diff --git a/clang/test/ExtractAPI/non_type_template.cpp 
b/clang/test/ExtractAPI/non_type_template.cpp
new file mode 100644
index 0000000000000..4e65eb790ca11
--- /dev/null
+++ b/clang/test/ExtractAPI/non_type_template.cpp
@@ -0,0 +1,313 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -extract-api --pretty-sgf 
--emit-sgf-symbol-labels-for-testing \
+// RUN:   -triple arm64-apple-macosx -std=c++17 -x c++-header %s -o 
%t/output.symbols.json -verify
+
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix FOO
+template <typename T, int N = 4> class Foo { };
+// FOO-LABEL: "!testLabel": "c:@ST>2#T#NI@Foo"
+// FOO:      "declarationFragments": [
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "keyword",
+// FOO-NEXT:     "spelling": "template"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": " <"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "keyword",
+// FOO-NEXT:     "spelling": "typename"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": " "
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "genericParameter",
+// FOO-NEXT:     "spelling": "T"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": ", "
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "typeIdentifier",
+// FOO-NEXT:     "preciseIdentifier": "c:I",
+// FOO-NEXT:     "spelling": "int"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": " "
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "genericParameter",
+// FOO-NEXT:     "spelling": "N"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": " = 4> "
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "keyword",
+// FOO-NEXT:     "spelling": "class"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": " "
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "identifier",
+// FOO-NEXT:     "spelling": "Foo"
+// FOO-NEXT:   },
+// FOO-NEXT:   {
+// FOO-NEXT:     "kind": "text",
+// FOO-NEXT:     "spelling": ";"
+// FOO-NEXT:   }
+// FOO-NEXT: ]
+
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix 
FOO-SPEC
+template <typename T> class Foo <T, 4> { };
+// FOO-SPEC-LABEL: "!testLabel": "c:@SP>1#T@Foo>#t0.0#VI4"
+// FOO-SPEC:      "declarationFragments": [
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "keyword",
+// FOO-SPEC-NEXT:     "spelling": "template"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "text",
+// FOO-SPEC-NEXT:     "spelling": " <"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "keyword",
+// FOO-SPEC-NEXT:     "spelling": "typename"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "text",
+// FOO-SPEC-NEXT:     "spelling": " "
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "genericParameter",
+// FOO-SPEC-NEXT:     "spelling": "T"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "text",
+// FOO-SPEC-NEXT:     "spelling": "> "
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "keyword",
+// FOO-SPEC-NEXT:     "spelling": "class"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "text",
+// FOO-SPEC-NEXT:     "spelling": " "
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "identifier",
+// FOO-SPEC-NEXT:     "spelling": "Foo"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "text",
+// FOO-SPEC-NEXT:     "spelling": "<"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "typeIdentifier",
+// FOO-SPEC-NEXT:     "preciseIdentifier": "c:t0.0",
+// FOO-SPEC-NEXT:     "spelling": "T"
+// FOO-SPEC-NEXT:   },
+// FOO-SPEC-NEXT:   {
+// FOO-SPEC-NEXT:     "kind": "text",
+// FOO-SPEC-NEXT:     "spelling": ", 4>;"
+// FOO-SPEC-NEXT:   }
+// FOO-SPEC-NEXT: ]
+
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix NEST
+template <template <template <typename> typename> class... Bs> class 
NestedTemplateTemplateParamPack{ };
+// NEST-LABEL: "!testLabel": 
"c:@ST>1#pt>1#t>1#T@NestedTemplateTemplateParamPack"
+// NEST:      "declarationFragments": [
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "template"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": " <"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "template"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": " <"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "template"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": " <"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "typename"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": "> "
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "typename"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": "> "
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "class"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": "... "
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "genericParameter",
+// NEST-NEXT:     "spelling": "Bs"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": "> "
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "keyword",
+// NEST-NEXT:     "spelling": "class"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": " "
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "identifier",
+// NEST-NEXT:     "spelling": "NestedTemplateTemplateParamPack"
+// NEST-NEXT:   },
+// NEST-NEXT:   {
+// NEST-NEXT:     "kind": "text",
+// NEST-NEXT:     "spelling": ";"
+// NEST-NEXT:   }
+// NEST-NEXT: ]
+
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BAR
+template <template <typename> typename T = Foo> struct Bar { };
+// BAR-LABEL: "!testLabel": "c:@ST>1#t>1#T@Bar"
+// BAR:      "declarationFragments": [
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "keyword",
+// BAR-NEXT:     "spelling": "template"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": " <"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "keyword",
+// BAR-NEXT:     "spelling": "template"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": " <"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "keyword",
+// BAR-NEXT:     "spelling": "typename"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": "> "
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "keyword",
+// BAR-NEXT:     "spelling": "typename"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": " "
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "genericParameter",
+// BAR-NEXT:     "spelling": "T"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": " = "
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "typeIdentifier",
+// BAR-NEXT:     "preciseIdentifier": "c:@ST>2#T#NI@Foo",
+// BAR-NEXT:     "spelling": "Foo"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": "> "
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "keyword",
+// BAR-NEXT:     "spelling": "struct"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": " "
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "identifier",
+// BAR-NEXT:     "spelling": "Bar"
+// BAR-NEXT:   },
+// BAR-NEXT:   {
+// BAR-NEXT:     "kind": "text",
+// BAR-NEXT:     "spelling": ";"
+// BAR-NEXT:   }
+// BAR-NEXT: ]
+
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix VAR
+NestedTemplateTemplateParamPack<Bar, Bar> var;
+// VAR-LABEL: "!testLabel": "c:@var"
+// VAR:      "declarationFragments": [
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "typeIdentifier",
+// VAR-NEXT:     "preciseIdentifier": 
"c:@ST>1#pt>1#t>1#T@NestedTemplateTemplateParamPack",
+// VAR-NEXT:     "spelling": "NestedTemplateTemplateParamPack"
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "text",
+// VAR-NEXT:     "spelling": "<"
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "typeIdentifier",
+// VAR-NEXT:     "preciseIdentifier": "c:@ST>1#t>1#T@Bar",
+// VAR-NEXT:     "spelling": "Bar"
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "text",
+// VAR-NEXT:     "spelling": ", "
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "typeIdentifier",
+// VAR-NEXT:     "preciseIdentifier": "c:@ST>1#t>1#T@Bar",
+// VAR-NEXT:     "spelling": "Bar"
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "text",
+// VAR-NEXT:     "spelling": "> "
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "identifier",
+// VAR-NEXT:     "spelling": "var"
+// VAR-NEXT:   },
+// VAR-NEXT:   {
+// VAR-NEXT:     "kind": "text",
+// VAR-NEXT:     "spelling": ";"
+// VAR-NEXT:   }
+// VAR-NEXT: ]
+
+// expected-no-diagnostics

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to