Updated patch, based on last round of review comments.

http://reviews.llvm.org/D5621

Files:
  bindings/python/clang/cindex.py
  bindings/python/tests/cindex/test_cursor.py
  include/clang-c/Index.h
  test/Index/preamble_macro_template.cpp
  tools/c-index-test/c-index-test.c
  tools/libclang/CXCursor.cpp
  tools/libclang/libclang.exports
Index: bindings/python/clang/cindex.py
===================================================================
--- bindings/python/clang/cindex.py
+++ bindings/python/clang/cindex.py
@@ -1378,6 +1378,22 @@
         for i in range(0, num_args):
             yield conf.lib.clang_Cursor_getArgument(self, i)
 
+    def get_num_template_arguments(self):
+        """Returns the number of template args associated with this cursor."""
+        return conf.lib.clang_Cursor_getNumTemplateArguments(self)
+
+    def get_template_argument_type(self, num):
+        """Returns the CXType for the indicated template argument."""
+        return conf.lib.clang_Cursor_getTemplateArgumentType(self, num)
+
+    def get_template_argument_value(self, num):
+        """Returns the value of the indicated arg as a signed 64b integer."""
+        return conf.lib.clang_Cursor_getTemplateArgumentValue(self, num)
+
+    def get_template_argument_unsigned_value(self, num):
+        """Returns the value of the indicated arg as an unsigned 64b integer."""
+        return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, num)
+
     def get_children(self):
         """Return an iterator for accessing the children of this cursor."""
 
@@ -3314,6 +3330,23 @@
    Cursor,
    Cursor.from_result),
 
+  ("clang_Cursor_getNumTemplateArguments",
+   [Cursor],
+   c_int),
+
+  ("clang_Cursor_getTemplateArgumentType",
+   [Cursor, c_uint],
+   Type,
+   Type.from_result),
+
+  ("clang_Cursor_getTemplateArgumentValue",
+   [Cursor, c_uint],
+   c_longlong),
+
+  ("clang_Cursor_getTemplateArgumentUnsignedValue",
+   [Cursor, c_uint],
+   c_ulonglong),
+
   ("clang_Cursor_isBitField",
    [Cursor],
    bool),
Index: bindings/python/tests/cindex/test_cursor.py
===================================================================
--- bindings/python/tests/cindex/test_cursor.py
+++ bindings/python/tests/cindex/test_cursor.py
@@ -1,3 +1,4 @@
+import ctypes
 import gc
 
 from clang.cindex import CursorKind
@@ -244,6 +245,43 @@
     assert arguments[0].spelling == "i"
     assert arguments[1].spelling == "j"
 
+kTemplateArgTest = """\
+        template <int kInt, typename T, bool kBool>
+        void foo();
+
+        template<>
+        void foo<-7, float, true>();
+    """
+
+def test_get_num_template_arguments():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    foos = get_cursors(tu, 'foo')
+
+    assert foos[1].get_num_template_arguments() == 3
+
+def test_get_template_argument_type():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    foos = get_cursors(tu, 'foo')
+
+    assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT
+
+def test_get_template_argument_value():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    foos = get_cursors(tu, 'foo')
+
+    assert ctypes.c_int(foos[1].get_template_argument_value(0)).value == -7
+    assert ctypes.c_bool(foos[1].get_template_argument_value(2)).value == True
+
+
+def test_get_template_argument_unsigned_value():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    foos = get_cursors(tu, 'foo')
+
+    assert ctypes.c_uint(
+        foos[1].get_template_argument_unsigned_value(0)).value == 2 ** 32 - 7
+    assert ctypes.c_bool(
+        foos[1].get_template_argument_unsigned_value(2)).value == 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
+++ include/clang-c/Index.h
@@ -2939,6 +2939,87 @@
 CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i);
 
 /**
+ *\brief Returns the number of template args of a function decl representing a
+ * template specialization.
+ *
+ * If the argument cursor cannot be converted into a template function
+ * declaration, -1 is returned.
+ *
+ * For example, for the following declaration and specialization:
+ *   template <typename T, int kInt, bool kBool>
+ *   void foo() { ... }
+ *
+ *   template <>
+ *   void foo<float, -7, true>();
+ *
+ * When this is called, 3 will be returned.
+ */
+CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C);
+
+/**
+ * \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
+ * template argument has a kind of ArgKind::Integral, an invalid type is\
+ * returned (in debug mode, this will assert).
+ *
+ * For example, for the following declaration and specialization:
+ *   template <typename T, int kInt, bool kBool>
+ *   void foo() { ... }
+ *
+ *   template <>
+ *   void foo<float, -7, true>();
+ *
+ * If called with I = 0, "float", will be returned.
+ * Invalid types will be returned for I == 1 or 2.
+ */
+CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C,
+                                                           unsigned I);
+
+/**
+ * \brief Retrieve the value of an Integral TemplateArgument (of a function
+ *  decl representing a template specialization) as a signed long long.
+ *
+ * If the argument CXCursor does not represent a FunctionDecl whose I'th
+ * template argument has a kind of ArgKind::Integral, an undefined value will be
+ * returned (in debug mode, this call will fail an assert).
+ *
+ * For example, for the following declaration and specialization:
+ *   template <typename T, int kInt, bool kBool>
+ *   void foo() { ... }
+ *
+ *   template <>
+ *   void foo<float, -7, true>();
+ *
+ * If called with I = 1 or 2, -7 or true will be returned, respectively.
+ * For I == 0, an invalid value will be returned or an assert will be triggered.
+ */
+CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C,
+                                                               unsigned I);
+
+/**
+ * \brief Retrieve the value of an Integral TemplateArgument (of a function
+ *  decl representing a template specialization) as an unsigned long long.
+ *
+ * If the argument CXCursor does not represent an TemplateArgument with a kind
+ * ArgKind::Integral, an undefined value will be returned (in debug mode, this
+ * call will fail an assert).
+ *
+ * For example, for the following declaration and specialization:
+ *   template <typename T, int kInt, bool kBool>
+ *   void foo() { ... }
+ *
+ *   template <>
+ *   void foo<float, -7, true>();
+ *
+ * If called with I = 1 or 2, 2^32 - 7 or true will be returned, respectively.
+ * For I == 0, an invalid value will be returned or an assert will be triggered.
+ */
+CINDEX_LINKAGE unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(
+    CXCursor C, unsigned I);
+
+/**
  * \brief Determine whether two CXTypes represent the same type.
  *
  * \returns non-zero if the CXTypes represent the same type and
Index: test/Index/preamble_macro_template.cpp
===================================================================
--- test/Index/preamble_macro_template.cpp
+++ test/Index/preamble_macro_template.cpp
@@ -4,7 +4,7 @@
 
 // RUN: c-index-test -write-pch %t.pch -fno-delayed-template-parsing -x c++-header %S/Inputs/preamble_macro_template.h
 // RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s 2>&1 | tee %t.check.txt | FileCheck %s
-// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] Extent=[4:1 - 6:2]
+// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] [Template arg 0: type: int] Extent=[4:1 - 6:2]
 // CHECK: preamble_macro_template.h:4:13: ParmDecl=p:4:13 (Definition) Extent=[4:10 - 4:14]
 // CHECK: preamble_macro_template.h:4:16: CompoundStmt= Extent=[4:16 - 6:2]
 // CHECK: preamble_macro_template.h:5:3: CStyleCastExpr= Extent=[5:3 - 5:27]
Index: tools/c-index-test/c-index-test.c
===================================================================
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -639,6 +639,18 @@
   return (int)lhs->col - (int)rhs->col;
 }
 
+typedef struct {
+  enum CXCursorKind *TemplateParamKinds;
+  unsigned CurrentIndex;
+} VisitTemplateParamsData;
+
+enum CXChildVisitResult visitTemplateParams(CXCursor Cursor, CXCursor Parent,
+                                            CXClientData ClientData) {
+  VisitTemplateParamsData *VTPD = (VisitTemplateParamsData*) ClientData;
+  VTPD->TemplateParamKinds[VTPD->CurrentIndex++] = clang_getCursorKind(Cursor);
+  return CXChildVisit_Continue;
+}
+
 static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
   CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
   if (clang_isInvalid(Cursor.kind)) {
@@ -796,15 +808,41 @@
       printf(" [access=%s isVirtual=%s]", accessStr,
              isVirtual ? "true" : "false");
     }
-    
+
     SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
     if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
       CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
       CXString Name = clang_getCursorSpelling(SpecializationOf);
       clang_getSpellingLocation(Loc, 0, &line, &column, 0);
-      printf(" [Specialization of %s:%d:%d]", 
+      printf(" [Specialization of %s:%d:%d]",
              clang_getCString(Name), line, column);
       clang_disposeString(Name);
+
+      if (Cursor.kind == CXCursor_FunctionDecl) {
+        // Collect the template parameter kinds from the base template.
+        unsigned NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
+        enum CXCursorKind *TemplateParamKinds = (enum CXCursorKind*)
+            malloc(NumTemplateArgs * sizeof(enum CXCursorKind));
+        VisitTemplateParamsData VTPD;
+        VTPD.TemplateParamKinds = TemplateParamKinds;
+        VTPD.CurrentIndex = 0;
+        clang_visitChildren(SpecializationOf, visitTemplateParams,
+                            &VTPD);
+
+        for (unsigned I = 0; I < NumTemplateArgs; I++) {
+          if (TemplateParamKinds[I] == CXCursor_TemplateTypeParameter) {
+            CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
+            CXString S = clang_getTypeSpelling(T);
+            printf(" [Template arg %d: type: %s]", I, clang_getCString(S));
+            clang_disposeString(S);
+          } else if (TemplateParamKinds[I] ==
+                     CXCursor_NonTypeTemplateParameter) {
+            printf(" [Template arg %d: intval: %lld]",
+                   I, clang_Cursor_getTemplateArgumentValue(Cursor, I));
+          }
+        }
+        free(TemplateParamKinds);
+      }
     }
 
     clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -1071,6 +1071,103 @@
   return clang_getNullCursor();
 }
 
+int clang_Cursor_getNumTemplateArguments(CXCursor C) {
+  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+    assert(0 && "Cursor is not a FunctionDecl");
+    return -1;
+  }
+
+  const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+      getCursorDecl(C));
+  if (!FD) {
+    assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl");
+    return -1;
+  }
+
+  const FunctionTemplateSpecializationInfo* SpecInfo =
+      FD->getTemplateSpecializationInfo();
+  if (!SpecInfo) {
+    assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved");
+    return -1;
+  }
+
+  return SpecInfo->TemplateArguments->size();
+}
+
+CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
+  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+    assert(0 && "Cursor is not a FunctionDecl");
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+
+  const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+      getCursorDecl(C));
+  if (!FD) {
+    assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl");
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+
+  const FunctionTemplateSpecializationInfo* SpecInfo =
+      FD->getTemplateSpecializationInfo();
+  if (!SpecInfo) {
+    assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved");
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+
+  if (I >= SpecInfo->TemplateArguments->size()) {
+    assert(0 && "Invalid template argument index");
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+
+  TemplateArgument TA = SpecInfo->TemplateArguments->get(I);
+  if (TA.getKind() != TemplateArgument::Type) {
+    assert(0 && "Passed template argument is not a Type");
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+
+  return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C));
+}
+
+long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
+  return static_cast<long long>(
+      clang_Cursor_getTemplateArgumentUnsignedValue(C, I));
+}
+
+unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
+                                                                 unsigned I) {
+  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+    assert(0 && "Cursor is not a FunctionDecl");
+    return 0;
+  }
+
+  const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+      getCursorDecl(C));
+  if (!FD) {
+    assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl");
+    return 0;
+  }
+
+  const FunctionTemplateSpecializationInfo* SpecInfo =
+      FD->getTemplateSpecializationInfo();
+  if (!SpecInfo) {
+    assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved");
+    return 0;
+  }
+
+  if (I >= SpecInfo->TemplateArguments->size()) {
+    assert(0 && "Invalid template argument index");
+    return 0;
+  }
+
+  TemplateArgument TA = SpecInfo->TemplateArguments->get(I);
+  if (TA.getKind() != TemplateArgument::Integral) {
+    assert(0 && "Passed template argument is not Integral");
+    return 0;
+  }
+
+  return TA.getAsIntegral().getZExtValue();
+}
+
 } // end: extern "C"
 
 //===----------------------------------------------------------------------===//
Index: tools/libclang/libclang.exports
===================================================================
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -7,6 +7,10 @@
 clang_CXXMethod_isStatic
 clang_CXXMethod_isVirtual
 clang_Cursor_getArgument
+clang_Cursor_getNumTemplateArguments
+clang_Cursor_getTemplateArgumentType
+clang_Cursor_getTemplateArgumentValue
+clang_Cursor_getTemplateArgumentUnsignedValue
 clang_Cursor_getBriefCommentText
 clang_Cursor_getCommentRange
 clang_Cursor_getMangling
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to