[clang] [libclang] Add clang_Type_getDependentSizeExpr (PR #212648)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 30 06:20:27 PDT 2026


https://github.com/w-utter updated https://github.com/llvm/llvm-project/pull/212648

>From ded00301e58cb228a318e0c008bdcd33a4c836c7 Mon Sep 17 00:00:00 2001
From: will <104373134+w-utter at users.noreply.github.com>
Date: Wed, 29 Jul 2026 08:52:56 +1000
Subject: [PATCH 1/2] [libclang] Add clang_Type_getDependentSizeExpr

---
 clang/include/clang-c/Index.h     |  8 ++++++++
 clang/tools/libclang/CXType.cpp   | 26 ++++++++++++++++++++++++++
 clang/tools/libclang/libclang.map |  1 +
 3 files changed, 35 insertions(+)

diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 8427236e0b444..3c2ae30d9bbb9 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3734,6 +3734,14 @@ CINDEX_LINKAGE CXType clang_Type_getModifiedType(CXType T);
  */
 CINDEX_LINKAGE CXType clang_Type_getValueType(CXType CT);
 
+
+/**
+ *  Gets the expression associated with this dependent sized array
+ *
+ *  If a non-dependent type is passed in, an invalid cursor is returned.
+ */
+CINDEX_LINKAGE CXCursor clang_Type_getDependentSizeExpr(CXType CT);
+
 /**
  * Return the offset of the field represented by the Cursor.
  *
diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp
index 0063939dec423..52e813ea3c795 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -912,6 +912,32 @@ long long clang_getNumElements(CXType CT) {
   return result;
 }
 
+CXCursor clang_Type_getDependentSizeExpr(CXType CT) {
+  QualType T = GetQualType(CT);
+  const Type *TP = T.getTypePtrOrNull();
+
+  if (!TP)
+    return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+
+  const Expr* E = nullptr;
+
+  switch (TP->getTypeClass()) {
+  case Type::DependentSizedArray:
+    E = cast<DependentSizedArrayType> (TP)->getSizeExpr();
+    break;
+  case Type::DependentSizedExtVector:
+    E = cast<DependentSizedExtVectorType> (TP)->getSizeExpr();
+    break;
+  default:
+    break;
+  }
+
+  if (!E) 
+    return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
+  
+  return cxcursor::MakeCXCursor(E, nullptr, GetTU(CT));
+}
+
 CXType clang_getArrayElementType(CXType CT) {
   QualType ET = QualType();
   QualType T = GetQualType(CT);
diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map
index 57f281096929d..4864cb6da5929 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -461,6 +461,7 @@ LLVM_23 {
   global:
     clang_ModuleCache_prune;
     clang_ModuleCache_pruneWithCallback;
+    clang_Type_getDependentSizeExpr;
 };
 
 # Example of how to add a new symbol version entry.  If you do add a new symbol

>From 34d1bffc3e0253c474cc774ce327c8ded059b5a6 Mon Sep 17 00:00:00 2001
From: will <104373134+w-utter at users.noreply.github.com>
Date: Thu, 30 Jul 2026 23:20:03 +1000
Subject: [PATCH 2/2] [libclang] support getting template argument kind &
 values from CXType

---
 clang/include/clang-c/Index.h             | 31 +++++++++++
 clang/tools/libclang/CMakeLists.txt       |  1 +
 clang/tools/libclang/CXCursor.cpp         | 52 +++---------------
 clang/tools/libclang/CXTemplateArgument.h | 62 ++++++++++++++++++++++
 clang/tools/libclang/CXType.cpp           | 64 ++++++++++++++++-------
 clang/tools/libclang/libclang.map         |  5 ++
 6 files changed, 150 insertions(+), 65 deletions(-)
 create mode 100644 clang/tools/libclang/CXTemplateArgument.h

diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 3c2ae30d9bbb9..6c53d1f7e5233 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3251,6 +3251,15 @@ CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C);
 CINDEX_LINKAGE enum CXTemplateArgumentKind
 clang_Cursor_getTemplateArgumentKind(CXCursor C, unsigned I);
 
+/**
+ * Retrieve the kind of the I'th template argument of the CXType CT.
+ *
+ * If the argument CXType does not represent a template specialization,
+ * an invalid template argument kind is returned.
+ */
+CINDEX_LINKAGE enum CXTemplateArgumentKind
+clang_Type_getTemplateArgumentKind(CXType CT, unsigned I);
+
 /**
  * Retrieve a CXType representing the type of a TemplateArgument of a
  *  function decl representing a template specialization.
@@ -3293,6 +3302,17 @@ CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C,
 CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C,
                                                                unsigned I);
 
+/**
+ * Retrieve the value of an Integral TemplateArgument (of a function
+ *  decl representing a template specialization) as a signed long long.
+ *
+ * It is undefined to call this function on a CXType that does not represent a
+ * FunctionDecl, StructDecl, ClassDecl or ClassTemplatePartialSpecialization
+ * whose I'th template argument is not an integral value.
+ */
+CINDEX_LINKAGE long long clang_Type_getTemplateArgumentValue(CXType CT,
+                                                          unsigned index);
+
 /**
  * Retrieve the value of an Integral TemplateArgument (of a function
  *  decl representing a template specialization) as an unsigned long long.
@@ -3314,6 +3334,17 @@ CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C,
 CINDEX_LINKAGE unsigned long long
 clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, unsigned I);
 
+/**
+ * Retrieve the value of an Integral TemplateArgument (of a function
+ *  decl representing a template specialization) as an unsigned long long.
+ *
+ * It is undefined to call this function on a CXType that does not represent a
+ * FunctionDecl, StructDecl, ClassDecl or ClassTemplatePartialSpecialization
+ * whose I'th template argument is not an integral value.
+ */
+CINDEX_LINKAGE unsigned long long
+clang_Type_getTemplateArgumentUnsignedValue(CXType C, unsigned I);
+
 /**
  * Determine whether two CXTypes represent the same type.
  *
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index 38f577499dd22..a1e9ea43d2d8e 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -51,6 +51,7 @@ set(SOURCES
   CXLoadedDiagnostic.h
   CXSourceLocation.h
   CXString.h
+  CXTemplateArgument.h
   CXTranslationUnit.h
   CXType.h
   Index_Internal.h
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index fb0b3c1502574..6bf9fe24d2fb1 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -14,6 +14,7 @@
 
 #include "CXCursor.h"
 #include "CXString.h"
+#include "CXTemplateArgument.h"
 #include "CXTranslationUnit.h"
 #include "CXType.h"
 #include "clang-c/Index.h"
@@ -1529,38 +1530,12 @@ static int clang_Cursor_getTemplateArgument(CXCursor C, unsigned I,
   return CXGetTemplateArgumentStatus_BadDeclCast;
 }
 
-enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,
-                                                                 unsigned I) {
+enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C, unsigned I) {
   TemplateArgument TA;
   if (clang_Cursor_getTemplateArgument(C, I, &TA)) {
     return CXTemplateArgumentKind_Invalid;
   }
-
-  switch (TA.getKind()) {
-  case TemplateArgument::Null:
-    return CXTemplateArgumentKind_Null;
-  case TemplateArgument::Type:
-    return CXTemplateArgumentKind_Type;
-  case TemplateArgument::Declaration:
-    return CXTemplateArgumentKind_Declaration;
-  case TemplateArgument::NullPtr:
-    return CXTemplateArgumentKind_NullPtr;
-  case TemplateArgument::Integral:
-    return CXTemplateArgumentKind_Integral;
-  case TemplateArgument::StructuralValue:
-    // FIXME: Expose these values.
-    return CXTemplateArgumentKind_Invalid;
-  case TemplateArgument::Template:
-    return CXTemplateArgumentKind_Template;
-  case TemplateArgument::TemplateExpansion:
-    return CXTemplateArgumentKind_TemplateExpansion;
-  case TemplateArgument::Expression:
-    return CXTemplateArgumentKind_Expression;
-  case TemplateArgument::Pack:
-    return CXTemplateArgumentKind_Pack;
-  }
-
-  return CXTemplateArgumentKind_Invalid;
+  return GetTemplateArgumentKind(TA);
 }
 
 CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
@@ -1569,12 +1544,7 @@ CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
       CXGetTemplateArgumentStatus_Success) {
     return cxtype::MakeCXType(QualType(), getCursorTU(C));
   }
-
-  if (TA.getKind() != TemplateArgument::Type) {
-    return cxtype::MakeCXType(QualType(), getCursorTU(C));
-  }
-
-  return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C));
+  return GetTemplateArgumentType(TA, getCursorTU(C));
 }
 
 long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
@@ -1585,12 +1555,7 @@ long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
     return 0;
   }
 
-  if (TA.getKind() != TemplateArgument::Integral) {
-    assert(0 && "Passed template argument is not Integral");
-    return 0;
-  }
-
-  return TA.getAsIntegral().getSExtValue();
+  return GetTemplateArgumentValue(TA);
 }
 
 unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
@@ -1602,12 +1567,7 @@ unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
     return 0;
   }
 
-  if (TA.getKind() != TemplateArgument::Integral) {
-    assert(0 && "Passed template argument is not Integral");
-    return 0;
-  }
-
-  return TA.getAsIntegral().getZExtValue();
+  return GetTemplateArgumentUnsignedValue(TA);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/tools/libclang/CXTemplateArgument.h b/clang/tools/libclang/CXTemplateArgument.h
new file mode 100644
index 0000000000000..a5e2eab785dd4
--- /dev/null
+++ b/clang/tools/libclang/CXTemplateArgument.h
@@ -0,0 +1,62 @@
+#include "clang-c/Index.h"
+#include "clang/AST/TemplateBase.h"
+
+#include "CXCursor.h"
+#include "CXTranslationUnit.h"
+#include "CXType.h"
+
+using namespace clang;
+
+enum CXTemplateArgumentKind GetTemplateArgumentKind(TemplateArgument TA) {
+  switch (TA.getKind()) {
+  case TemplateArgument::Null:
+    return CXTemplateArgumentKind_Null;
+  case TemplateArgument::Type:
+    return CXTemplateArgumentKind_Type;
+  case TemplateArgument::Declaration:
+    return CXTemplateArgumentKind_Declaration;
+  case TemplateArgument::NullPtr:
+    return CXTemplateArgumentKind_NullPtr;
+  case TemplateArgument::Integral:
+    return CXTemplateArgumentKind_Integral;
+  case TemplateArgument::StructuralValue:
+    // FIXME: Expose these values.
+    return CXTemplateArgumentKind_Invalid;
+  case TemplateArgument::Template:
+    return CXTemplateArgumentKind_Template;
+  case TemplateArgument::TemplateExpansion:
+    return CXTemplateArgumentKind_TemplateExpansion;
+  case TemplateArgument::Expression:
+    return CXTemplateArgumentKind_Expression;
+  case TemplateArgument::Pack:
+    return CXTemplateArgumentKind_Pack;
+  }
+
+  return CXTemplateArgumentKind_Invalid;
+}
+
+CXType GetTemplateArgumentType(TemplateArgument TA, CXTranslationUnit TU) {
+  if (TA.getKind() != TemplateArgument::Type) {
+    return cxtype::MakeCXType(QualType(), TU);
+  }
+
+  return cxtype::MakeCXType(TA.getAsType(), TU);
+}
+
+long long GetTemplateArgumentValue(TemplateArgument TA) {
+  if (TA.getKind() != TemplateArgument::Integral) {
+    assert(0 && "Passed template argument is not Integral");
+    return 0;
+  }
+
+  return TA.getAsIntegral().getSExtValue();
+}
+
+unsigned long long GetTemplateArgumentUnsignedValue(TemplateArgument TA) {
+  if (TA.getKind() != TemplateArgument::Integral) {
+    assert(0 && "Passed template argument is not Integral");
+    return 0;
+  }
+
+  return TA.getAsIntegral().getZExtValue();
+}
diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp
index 52e813ea3c795..dd49fe15564c9 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -14,7 +14,9 @@
 #include "CIndexer.h"
 #include "CXCursor.h"
 #include "CXString.h"
+#include "CXTemplateArgument.h"
 #include "CXTranslationUnit.h"
+#include "clang-c/Index.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
@@ -201,25 +203,26 @@ GetTemplateArguments(QualType Type) {
   return std::nullopt;
 }
 
-static std::optional<QualType>
-TemplateArgumentToQualType(const TemplateArgument &A) {
-  if (A.getKind() == TemplateArgument::Type)
-    return A.getAsType();
-  return std::nullopt;
-}
+std::optional<TemplateArgument>
+FindTemplateArgumentAt(CXType CT, unsigned index) {
+  QualType T = GetQualType(CT);
+  if (T.isNull())
+    return std::nullopt;
+
+  auto TA = GetTemplateArguments(T);
+  if (!TA)
+    return std::nullopt;
 
-static std::optional<QualType>
-FindTemplateArgumentTypeAt(ArrayRef<TemplateArgument> TA, unsigned index) {
   unsigned current = 0;
-  for (const auto &A : TA) {
+  for (const auto &A : *TA) {
     if (A.getKind() == TemplateArgument::Pack) {
       if (index < current + A.pack_size())
-        return TemplateArgumentToQualType(A.getPackAsArray()[index - current]);
+        return A.getPackAsArray()[index - current];
       current += A.pack_size();
       continue;
     }
     if (current == index)
-      return TemplateArgumentToQualType(A);
+      return A;
     current++;
   }
   return std::nullopt;
@@ -1273,17 +1276,40 @@ int clang_Type_getNumTemplateArguments(CXType CT) {
   return GetTemplateArgumentArraySize(*TA);
 }
 
+enum CXTemplateArgumentKind clang_Type_getTemplateArgumentKind(CXType CT, unsigned index) {
+  const auto TA = FindTemplateArgumentAt(CT, index);
+
+  if (!TA) {
+    return CXTemplateArgumentKind_Invalid;
+  }
+  return GetTemplateArgumentKind(*TA);
+}
+
+long long clang_Type_getTemplateArgumentValue(CXType CT, unsigned index) {
+  const auto TA = FindTemplateArgumentAt(CT, index);
+
+  if (!TA) {
+    return 0;
+  }
+  return GetTemplateArgumentValue(*TA);
+}
+
+unsigned long long clang_Type_getTemplateArgumentUnsignedValue(CXType CT, unsigned index) {
+  const auto TA = FindTemplateArgumentAt(CT, index);
+
+  if (!TA) {
+    return 0;
+  }
+  return GetTemplateArgumentValue(*TA);
+}
+
 CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) {
-  QualType T = GetQualType(CT);
-  if (T.isNull())
-    return MakeCXType(QualType(), GetTU(CT));
+  const auto TA = FindTemplateArgumentAt(CT, index);
 
-  auto TA = GetTemplateArguments(T);
-  if (!TA)
+  if (!TA) {
     return MakeCXType(QualType(), GetTU(CT));
-
-  std::optional<QualType> QT = FindTemplateArgumentTypeAt(*TA, index);
-  return MakeCXType(QT.value_or(QualType()), GetTU(CT));
+  }
+  return GetTemplateArgumentType(*TA, GetTU(CT));
 }
 
 CXType clang_Type_getObjCObjectBaseType(CXType CT) {
diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map
index 4864cb6da5929..7e51647d1f49c 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -462,8 +462,13 @@ LLVM_23 {
     clang_ModuleCache_prune;
     clang_ModuleCache_pruneWithCallback;
     clang_Type_getDependentSizeExpr;
+    clang_Type_getTemplateArgumentValue;
+    clang_Type_getTemplateArgumentUnsignedValue;
+    clang_Type_getTemplateArgumentKind;
 };
 
+
+
 # Example of how to add a new symbol version entry.  If you do add a new symbol
 # version, please update the example to depend on the version you added.
 # LLVM_X {



More information about the cfe-commits mailing list