[cfe-dev] Patch libclang: clang_Cursor_getTemplate* for struct/classes template specialization

Benoit Maurin maurinbe at gmail.com
Sat Aug 8 16:59:21 PDT 2015


Hi,

In the current state of things, clang_Cursor_getNumTemplateArguments and co
only works for functions.
It would be nice for it to also work for struct/class template
specializations.
A patch doing just that is attached.
It is rather short and there are also tests included (for python lib)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150809/470b6d76/attachment.html>
-------------- next part --------------
Index: bindings/python/tests/cindex/test_cursor.py
===================================================================
--- bindings/python/tests/cindex/test_cursor.py	(revision 244406)
+++ bindings/python/tests/cindex/test_cursor.py	(working copy)
@@ -252,6 +252,15 @@
 
         template<>
         void foo<-7, float, true>();
+
+        template <int kInt, typename T, bool kBool>
+        struct bar{
+            int a=kInt;
+            T b;
+            bool c=kBool;
+        };
+
+        bar<-7, float, true> X;
     """
 
 def test_get_num_template_arguments():
@@ -288,6 +297,40 @@
     assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7
     assert foos[1].get_template_argument_unsigned_value(2) == True
 
+def test_get_num_template_arguments_struct():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    bar = get_cursor(tu, 'X').type.get_declaration()
+
+    assert bar.get_num_template_arguments() == 3
+
+def test_get_template_argument_kind_struct():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    bar = get_cursor(tu, 'X').type.get_declaration()
+
+    assert bar.get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL
+    assert bar.get_template_argument_kind(1) == TemplateArgumentKind.TYPE
+    assert bar.get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL
+
+def test_get_template_argument_type_struct():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    bar = get_cursor(tu, 'X').type.get_declaration()
+
+    assert bar.get_template_argument_type(1).kind == TypeKind.FLOAT
+
+def test_get_template_argument_value_struct():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    bar = get_cursor(tu, 'X').type.get_declaration()
+
+    assert bar.get_template_argument_value(0) == -7
+    assert bar.get_template_argument_value(2) == True
+
+def test_get_template_argument_unsigned_value_struct():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    bar = get_cursor(tu, 'X').type.get_declaration()
+
+    assert bar.get_template_argument_unsigned_value(0) == 2 ** 32 - 7
+    assert bar.get_template_argument_unsigned_value(2) == True
+
 def test_referenced():
     tu = get_tu('void foo(); void bar() { foo(); }')
     foo = get_cursor(tu, 'foo')
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h	(revision 244406)
+++ include/clang-c/Index.h	(working copy)
@@ -3005,7 +3005,7 @@
 /**
  * \brief Retrieve the kind of the I'th template argument of the CXCursor C.
  *
- * If the argument CXCursor does not represent a FunctionDecl, an invalid
+ * If the argument CXCursor does not represent a FunctionDecl or a Struct/Class Decl, an invalid
  * template argument kind is returned.
  *
  * For example, for the following declaration and specialization:
@@ -3025,7 +3025,7 @@
  * \brief Retrieve a CXType representing the type of a TemplateArgument of a
  *  function decl representing a template specialization.
  *
- * If the argument CXCursor does not represent a FunctionDecl whose I'th
+ * If the argument CXCursor does not represent a FunctionDecl Struct/Class Decl whose I'th
  * template argument has a kind of CXTemplateArgKind_Integral, an invalid type
  * is returned.
  *
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp	(revision 244406)
+++ tools/libclang/CXCursor.cpp	(working copy)
@@ -1092,23 +1092,35 @@
 }
 
 int clang_Cursor_getNumTemplateArguments(CXCursor C) {
-  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
-    return -1;
-  }
+  if (clang_getCursorKind(C) == CXCursor_FunctionDecl) {
 
-  const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
-      getCursorDecl(C));
-  if (!FD) {
-    return -1;
-  }
+    const FunctionDecl *FD =
+        llvm::dyn_cast_or_null<clang::FunctionDecl>(getCursorDecl(C));
+    if (!FD) {
+      return -1;
+    }
 
-  const FunctionTemplateSpecializationInfo* SpecInfo =
-      FD->getTemplateSpecializationInfo();
-  if (!SpecInfo) {
+    const FunctionTemplateSpecializationInfo *SpecInfo =
+        FD->getTemplateSpecializationInfo();
+    if (!SpecInfo) {
+      return -1;
+    }
+
+    return SpecInfo->TemplateArguments->size();
+  } else if (clang_getCursorKind(C) == CXCursor_StructDecl ||
+             clang_getCursorKind(C) == CXCursor_ClassDecl) {
+
+    const ClassTemplateSpecializationDecl *Decl =
+        llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
+            getCursorDecl(C));
+    if (!Decl) {
+      return -1;
+    }
+
+    return Decl->getTemplateArgs().size();
+  } else {
     return -1;
   }
-
-  return SpecInfo->TemplateArguments->size();
 }
 
 enum CXGetTemplateArgumentStatus {
@@ -1116,10 +1128,10 @@
   CXGetTemplateArgumentStatus_Success = 0,
 
   /** \brief The specified cursor did not represent a FunctionDecl. */
-  CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1,
+  CXGetTemplateArgumentStatus_CursorNotSupportedDecl = -1,
 
   /** \brief The specified cursor was not castable to a FunctionDecl. */
-  CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2,
+  CXGetTemplateArgumentStatus_BadDeclCast = -2,
 
   /** \brief A NULL FunctionTemplateSpecializationInfo was retrieved. */
   CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3,
@@ -1130,28 +1142,43 @@
 
 static int clang_Cursor_getTemplateArgument(
     CXCursor C, unsigned I, TemplateArgument *TA) {
-  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
-    return CXGetTemplateArgumentStatus_CursorNotFunctionDecl;
-  }
+  if (clang_getCursorKind(C) == CXCursor_FunctionDecl) {
 
-  const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
-      getCursorDecl(C));
-  if (!FD) {
-    return CXGetTemplateArgumentStatus_BadFunctionDeclCast;
-  }
+    const FunctionDecl *FD =
+        llvm::dyn_cast_or_null<clang::FunctionDecl>(getCursorDecl(C));
+    if (!FD) {
+      return CXGetTemplateArgumentStatus_BadDeclCast;
+    }
 
-  const FunctionTemplateSpecializationInfo* SpecInfo =
-      FD->getTemplateSpecializationInfo();
-  if (!SpecInfo) {
-    return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
-  }
+    const FunctionTemplateSpecializationInfo *SpecInfo =
+        FD->getTemplateSpecializationInfo();
+    if (!SpecInfo) {
+      return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+    }
 
-  if (I >= SpecInfo->TemplateArguments->size()) {
-    return CXGetTemplateArgumentStatus_InvalidIndex;
+    if (I >= SpecInfo->TemplateArguments->size()) {
+      return CXGetTemplateArgumentStatus_InvalidIndex;
+    }
+
+    *TA = SpecInfo->TemplateArguments->get(I);
+    return 0;
+  } else if (clang_getCursorKind(C) == CXCursor_StructDecl ||
+             clang_getCursorKind(C) == CXCursor_ClassDecl) {
+
+    const ClassTemplateSpecializationDecl *Decl =
+        llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
+            getCursorDecl(C));
+    if (!Decl) {
+      return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+    }
+
+    if (I >= Decl->getTemplateArgs().size())
+      return CXGetTemplateArgumentStatus_InvalidIndex;
+    *TA = Decl->getTemplateArgs().get(I);
+    return 0;
+  } else {
+    return CXGetTemplateArgumentStatus_CursorNotSupportedDecl;
   }
-
-  *TA = SpecInfo->TemplateArguments->get(I);
-  return 0;
 }
 
 enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,


More information about the cfe-dev mailing list