r219529 - Add libclang capabilities to retriete template arguments from specializations.

Eli Bendersky eliben at google.com
Fri Oct 10 13:01:06 PDT 2014


Author: eliben
Date: Fri Oct 10 15:01:05 2014
New Revision: 219529

URL: http://llvm.org/viewvc/llvm-project?rev=219529&view=rev
Log:
Add libclang capabilities to retriete template arguments from specializations.

Includes Python bindings.

Reviewed in http://reviews.llvm.org/D5621
Patch by Rob Springer


Modified:
    cfe/trunk/bindings/python/clang/cindex.py
    cfe/trunk/bindings/python/tests/cindex/test_cursor.py
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/test/Index/index-templates.cpp
    cfe/trunk/test/Index/preamble_macro_template.cpp
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/CXCursor.cpp
    cfe/trunk/tools/libclang/libclang.exports

Modified: cfe/trunk/bindings/python/clang/cindex.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/clang/cindex.py?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/bindings/python/clang/cindex.py (original)
+++ cfe/trunk/bindings/python/clang/cindex.py Fri Oct 10 15:01:05 2014
@@ -496,24 +496,28 @@ class TokenKind(object):
         setattr(TokenKind, name, kind)
 
 ### Cursor Kinds ###
-
-class CursorKind(object):
-    """
-    A CursorKind describes the kind of entity that a cursor points to.
+class BaseEnumeration(object):
     """
+    Common base class for named enumerations held in sync with Index.h values.
 
-    # The unique kind objects, indexed by id.
+    Subclasses must define their own _kinds and _name_map members, as:
     _kinds = []
     _name_map = None
+    These values hold the per-subclass instances and value-to-name mappings,
+    respectively.
+
+    """
 
     def __init__(self, value):
-        if value >= len(CursorKind._kinds):
-            CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1)
-        if CursorKind._kinds[value] is not None:
-            raise ValueError,'CursorKind already loaded'
+        if value >= len(self.__class__._kinds):
+            self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1)
+        if self.__class__._kinds[value] is not None:
+            raise ValueError,'{0} value {1} already loaded'.format(
+                str(self.__class__), value)
         self.value = value
-        CursorKind._kinds[value] = self
-        CursorKind._name_map = None
+        self.__class__._kinds[value] = self
+        self.__class__._name_map = None
+
 
     def from_param(self):
         return self.value
@@ -523,16 +527,29 @@ class CursorKind(object):
         """Get the enumeration name of this cursor kind."""
         if self._name_map is None:
             self._name_map = {}
-            for key,value in CursorKind.__dict__.items():
-                if isinstance(value,CursorKind):
+            for key, value in self.__class__.__dict__.items():
+                if isinstance(value, self.__class__):
                     self._name_map[value] = key
         return self._name_map[self]
 
-    @staticmethod
-    def from_id(id):
-        if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
-            raise ValueError,'Unknown cursor kind %d' % id
-        return CursorKind._kinds[id]
+    @classmethod
+    def from_id(cls, id):
+        if id >= len(cls._kinds) or cls._kinds[id] is None:
+            raise ValueError,'Unknown template argument kind %d' % id
+        return cls._kinds[id]
+
+    def __repr__(self):
+        return '%s.%s' % (self.__class__, self.name,)
+
+
+class CursorKind(BaseEnumeration):
+    """
+    A CursorKind describes the kind of entity that a cursor points to.
+    """
+
+    # The required BaseEnumeration declarations.
+    _kinds = []
+    _name_map = None
 
     @staticmethod
     def get_all_kinds():
@@ -578,11 +595,6 @@ class CursorKind(object):
     def __repr__(self):
         return 'CursorKind.%s' % (self.name,)
 
-# FIXME: Is there a nicer way to expose this enumeration? We could potentially
-# represent the nested structure, or even build a class hierarchy. The main
-# things we want for sure are (a) simple external access to kinds, (b) a place
-# to hang a description and name, (c) easy to keep in sync with Index.h.
-
 ###
 # Declaration Kinds
 
@@ -1101,6 +1113,24 @@ CursorKind.INCLUSION_DIRECTIVE = CursorK
 # A module import declaration.
 CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
 
+
+### Template Argument Kinds ###
+class TemplateArgumentKind(BaseEnumeration):
+    """
+    A TemplateArgumentKind describes the kind of entity that a template argument
+    represents.
+    """
+
+    # The required BaseEnumeration declarations.
+    _kinds = []
+    _name_map = None
+
+TemplateArgumentKind.NULL = TemplateArgumentKind(0)
+TemplateArgumentKind.TYPE = TemplateArgumentKind(1)
+TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2)
+TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3)
+TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4)
+
 ### Cursors ###
 
 class Cursor(Structure):
@@ -1378,6 +1408,27 @@ class Cursor(Structure):
         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_kind(self, num):
+        """Returns the TemplateArgumentKind for the indicated template
+        argument."""
+        return conf.lib.clang_Cursor_getTemplateArgumentKind(self, num)
+
+    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."""
 
@@ -1461,7 +1512,7 @@ class Cursor(Structure):
 
 ### C++ access specifiers ###
 
-class AccessSpecifier(object):
+class AccessSpecifier(BaseEnumeration):
     """
     Describes the access of a C++ class member
     """
@@ -1470,34 +1521,9 @@ class AccessSpecifier(object):
     _kinds = []
     _name_map = None
 
-    def __init__(self, value):
-        if value >= len(AccessSpecifier._kinds):
-            AccessSpecifier._kinds += [None] * (value - len(AccessSpecifier._kinds) + 1)
-        if AccessSpecifier._kinds[value] is not None:
-            raise ValueError,'AccessSpecifier already loaded'
-        self.value = value
-        AccessSpecifier._kinds[value] = self
-        AccessSpecifier._name_map = None
-
     def from_param(self):
         return self.value
 
-    @property
-    def name(self):
-        """Get the enumeration name of this access specifier."""
-        if self._name_map is None:
-            self._name_map = {}
-            for key,value in AccessSpecifier.__dict__.items():
-                if isinstance(value,AccessSpecifier):
-                    self._name_map[value] = key
-        return self._name_map[self]
-
-    @staticmethod
-    def from_id(id):
-        if id >= len(AccessSpecifier._kinds) or not AccessSpecifier._kinds[id]:
-            raise ValueError,'Unknown access specifier %d' % id
-        return AccessSpecifier._kinds[id]
-
     def __repr__(self):
         return 'AccessSpecifier.%s' % (self.name,)
 
@@ -1509,7 +1535,7 @@ AccessSpecifier.NONE = AccessSpecifier(4
 
 ### Type Kinds ###
 
-class TypeKind(object):
+class TypeKind(BaseEnumeration):
     """
     Describes the kind of type.
     """
@@ -1518,39 +1544,11 @@ class TypeKind(object):
     _kinds = []
     _name_map = None
 
-    def __init__(self, value):
-        if value >= len(TypeKind._kinds):
-            TypeKind._kinds += [None] * (value - len(TypeKind._kinds) + 1)
-        if TypeKind._kinds[value] is not None:
-            raise ValueError,'TypeKind already loaded'
-        self.value = value
-        TypeKind._kinds[value] = self
-        TypeKind._name_map = None
-
-    def from_param(self):
-        return self.value
-
-    @property
-    def name(self):
-        """Get the enumeration name of this cursor kind."""
-        if self._name_map is None:
-            self._name_map = {}
-            for key,value in TypeKind.__dict__.items():
-                if isinstance(value,TypeKind):
-                    self._name_map[value] = key
-        return self._name_map[self]
-
     @property
     def spelling(self):
         """Retrieve the spelling of this TypeKind."""
         return conf.lib.clang_getTypeKindSpelling(self.value)
 
-    @staticmethod
-    def from_id(id):
-        if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
-            raise ValueError,'Unknown type kind %d' % id
-        return TypeKind._kinds[id]
-
     def __repr__(self):
         return 'TypeKind.%s' % (self.name,)
 
@@ -1603,43 +1601,16 @@ TypeKind.VARIABLEARRAY = TypeKind(115)
 TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
 TypeKind.MEMBERPOINTER = TypeKind(117)
 
-class RefQualifierKind(object):
+class RefQualifierKind(BaseEnumeration):
     """Describes a specific ref-qualifier of a type."""
 
     # The unique kind objects, indexed by id.
     _kinds = []
     _name_map = None
 
-    def __init__(self, value):
-        if value >= len(RefQualifierKind._kinds):
-            num_kinds = value - len(RefQualifierKind._kinds) + 1
-            RefQualifierKind._kinds += [None] * num_kinds
-        if RefQualifierKind._kinds[value] is not None:
-            raise ValueError, 'RefQualifierKind already loaded'
-        self.value = value
-        RefQualifierKind._kinds[value] = self
-        RefQualifierKind._name_map = None
-
     def from_param(self):
         return self.value
 
-    @property
-    def name(self):
-        """Get the enumeration name of this kind."""
-        if self._name_map is None:
-            self._name_map = {}
-            for key, value in RefQualifierKind.__dict__.items():
-                if isinstance(value, RefQualifierKind):
-                    self._name_map[value] = key
-        return self._name_map[self]
-
-    @staticmethod
-    def from_id(id):
-        if (id >= len(RefQualifierKind._kinds) or
-                RefQualifierKind._kinds[id] is None):
-            raise ValueError, 'Unknown type kind %d' % id
-        return RefQualifierKind._kinds[id]
-
     def __repr__(self):
         return 'RefQualifierKind.%s' % (self.name,)
 
@@ -3314,6 +3285,27 @@ functionList = [
    Cursor,
    Cursor.from_result),
 
+  ("clang_Cursor_getNumTemplateArguments",
+   [Cursor],
+   c_int),
+
+  ("clang_Cursor_getTemplateArgumentKind",
+   [Cursor, c_uint],
+   TemplateArgumentKind.from_id),
+
+  ("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),

Modified: cfe/trunk/bindings/python/tests/cindex/test_cursor.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/python/tests/cindex/test_cursor.py?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/bindings/python/tests/cindex/test_cursor.py (original)
+++ cfe/trunk/bindings/python/tests/cindex/test_cursor.py Fri Oct 10 15:01:05 2014
@@ -1,6 +1,8 @@
+import ctypes
 import gc
 
 from clang.cindex import CursorKind
+from clang.cindex import TemplateArgumentKind
 from clang.cindex import TranslationUnit
 from clang.cindex import TypeKind
 from .util import get_cursor
@@ -244,6 +246,48 @@ def test_get_arguments():
     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_kind():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    foos = get_cursors(tu, 'foo')
+
+    assert foos[1].get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL
+    assert foos[1].get_template_argument_kind(1) == TemplateArgumentKind.TYPE
+    assert foos[1].get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL
+
+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 foos[1].get_template_argument_value(0) == -7
+    assert foos[1].get_template_argument_value(2) == True
+
+def test_get_template_argument_unsigned_value():
+    tu = get_tu(kTemplateArgTest, lang='cpp')
+    foos = get_cursors(tu, 'foo')
+
+    assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7
+    assert foos[1].get_template_argument_unsigned_value(2) == True
+
 def test_referenced():
     tu = get_tu('void foo(); void bar() { foo(); }')
     foo = get_cursor(tu, 'foo')

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Fri Oct 10 15:01:05 2014
@@ -2943,6 +2943,124 @@ CINDEX_LINKAGE int clang_Cursor_getNumAr
 CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i);
 
 /**
+ * \brief Describes the kind of a template argument.
+ *
+ * See the definition of llvm::clang::TemplateArgument::ArgKind for full
+ * element descriptions.
+ */
+enum CXTemplateArgumentKind {
+  CXTemplateArgumentKind_Null,
+  CXTemplateArgumentKind_Type,
+  CXTemplateArgumentKind_Declaration,
+  CXTemplateArgumentKind_NullPtr,
+  CXTemplateArgumentKind_Integral,
+  CXTemplateArgumentKind_Template,
+  CXTemplateArgumentKind_TemplateExpansion,
+  CXTemplateArgumentKind_Expression,
+  CXTemplateArgumentKind_Pack,
+  /* Indicates an error case, preventing the kind from being deduced. */
+  CXTemplateArgumentKind_Invalid
+};
+
+/**
+ *\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>();
+ *
+ * The value 3 would be returned from this call.
+ */
+CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C);
+
+/**
+ * \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
+ * template argument kind 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>();
+ *
+ * For I = 0, 1, and 2, Type, Integral, and Integral will be returned,
+ * respectively.
+ */
+CINDEX_LINKAGE enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(
+    CXCursor C, unsigned I);
+
+/**
+ * \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 CXTemplateArgKind_Integral, an invalid type
+ * 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>();
+ *
+ * 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.
+ *
+ * It is undefined to call this function on a CXCursor that does not represent a
+ * FunctionDecl or whose I'th template argument is not an integral value.
+ *
+ * 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, this function's behavior is undefined.
+ */
+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.
+ *
+ * It is undefined to call this function on a CXCursor that does not represent a
+ * FunctionDecl or whose I'th template argument is not an integral value.
+ *
+ * For example, for the following declaration and specialization:
+ *   template <typename T, int kInt, bool kBool>
+ *   void foo() { ... }
+ *
+ *   template <>
+ *   void foo<float, 2147483649, true>();
+ *
+ * If called with I = 1 or 2, 2147483649 or true will be returned, respectively.
+ * For I == 0, this function's behavior is undefined.
+ */
+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

Modified: cfe/trunk/test/Index/index-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/index-templates.cpp?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/test/Index/index-templates.cpp (original)
+++ cfe/trunk/test/Index/index-templates.cpp Fri Oct 10 15:01:05 2014
@@ -100,6 +100,16 @@ template class Pair<int, int>;
 template<typename T, typename U>
 struct SuperPair : Pair<int, int>, Pair<T, U> { };
 
+enum FxnTmplEnum {
+  FxnTmplEnum_A, FxnTmplEnum_B, FxnTmplEnum_C,
+};
+template <typename T, int I, FxnTmplEnum, int E>
+void foo(T Value) {}
+
+static const int FxnTmpl_Var = 7;
+template <>
+void foo<float, 9, FxnTmplEnum_B, FxnTmpl_Var + 7>(float Value);
+
 // RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-LOAD %s
 // CHECK-LOAD: index-templates.cpp:4:6: FunctionTemplate=f:4:6 Extent=[3:1 - 4:22]
 // CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:10 - 3:20]
@@ -178,7 +188,7 @@ struct SuperPair : Pair<int, int>, Pair<
 // CHECK-LOAD: index-templates.cpp:100:31: TemplateTypeParameter=U:100:31 (Definition) Extent=[100:22 - 100:32]
 // CHECK-LOAD: index-templates.cpp:101:20: C++ base class specifier=Pair<int, int>:98:16 [access=public isVirtual=false] Extent=[101:20 - 101:34]
 // CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair<T, U>:76:8 [access=public isVirtual=false] Extent=[101:36 - 101:46]
-
+// CHECK-LOAD: index-templates.cpp:111:6: FunctionDecl=foo:111:6 [Specialization of foo:107:6] [Template arg 0: kind: 1, type: float] [Template arg 1: kind: 4, intval: 9] [Template arg 2: kind: 4, intval: 1] [Template arg 3: kind: 4, intval: 14] Extent=[110:1 - 111:64]
 
 // RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-USRS %s
 // CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_# Extent=[3:1 - 4:22]

Modified: cfe/trunk/test/Index/preamble_macro_template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/preamble_macro_template.cpp?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/test/Index/preamble_macro_template.cpp (original)
+++ cfe/trunk/test/Index/preamble_macro_template.cpp Fri Oct 10 15:01:05 2014
@@ -4,7 +4,7 @@ int main() { }
 
 // 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: kind: 1, 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]

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Fri Oct 10 15:01:05 2014
@@ -796,15 +796,42 @@ static void PrintCursor(CXCursor Cursor,
       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);
+        unsigned I;
+        for (I = 0; I < NumTemplateArgs; I++) {
+          enum CXTemplateArgumentKind TAK =
+              clang_Cursor_getTemplateArgumentKind(Cursor, I);
+          switch(TAK) {
+            case CXTemplateArgumentKind_Type:
+              {
+                CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
+                CXString S = clang_getTypeSpelling(T);
+                printf(" [Template arg %d: kind: %d, type: %s]",
+                       I, TAK, clang_getCString(S));
+                clang_disposeString(S);
+              }
+              break;
+            case CXTemplateArgumentKind_Integral:
+              printf(" [Template arg %d: kind: %d, intval: %lld]",
+                     I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
+              break;
+            default:
+              printf(" [Template arg %d: kind: %d]\n", I, TAK);
+          }
+        }
+      }
     }
 
     clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Fri Oct 10 15:01:05 2014
@@ -1074,6 +1074,140 @@ CXCursor clang_Cursor_getArgument(CXCurs
   return clang_getNullCursor();
 }
 
+int clang_Cursor_getNumTemplateArguments(CXCursor C) {
+  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+    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) {
+    return -1;
+  }
+
+  return SpecInfo->TemplateArguments->size();
+}
+
+enum CXGetTemplateArgumentStatus {
+  /** \brief The operation completed successfully */
+  CXGetTemplateArgumentStatus_Success = 0,
+
+  /** \brief The specified cursor did not represent a FunctionDecl. */
+  CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1,
+
+  /** \brief The specified cursor was not castable to a FunctionDecl. */
+  CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2,
+
+  /** \brief A NULL FunctionTemplateSpecializationInfo was retrieved. */
+  CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3,
+
+  /** \brief An invalid (OOB) argument index was specified */
+  CXGetTemplateArgumentStatus_InvalidIndex = -4
+};
+
+static int clang_Cursor_getTemplateArgument(
+    CXCursor C, unsigned I, TemplateArgument *TA) {
+  if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+    return CXGetTemplateArgumentStatus_CursorNotFunctionDecl;
+  }
+
+  const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+      getCursorDecl(C));
+  if (!FD) {
+    return CXGetTemplateArgumentStatus_BadFunctionDeclCast;
+  }
+
+  const FunctionTemplateSpecializationInfo* SpecInfo =
+      FD->getTemplateSpecializationInfo();
+  if (!SpecInfo) {
+    return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+  }
+
+  if (I >= SpecInfo->TemplateArguments->size()) {
+    return CXGetTemplateArgumentStatus_InvalidIndex;
+  }
+
+  *TA = SpecInfo->TemplateArguments->get(I);
+  return 0;
+}
+
+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::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 clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
+  TemplateArgument TA;
+  if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+      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));
+}
+
+long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
+  TemplateArgument TA;
+  if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+      CXGetTemplateArgumentStatus_Success) {
+    assert(0 && "Unable to retrieve TemplateArgument");
+    return 0;
+  }
+
+  if (TA.getKind() != TemplateArgument::Integral) {
+    assert(0 && "Passed template argument is not Integral");
+    return 0;
+  }
+
+  return TA.getAsIntegral().getSExtValue();
+}
+
+unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
+                                                                 unsigned I) {
+  TemplateArgument TA;
+  if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+      CXGetTemplateArgumentStatus_Success) {
+    assert(0 && "Unable to retrieve TemplateArgument");
+    return 0;
+  }
+
+  if (TA.getKind() != TemplateArgument::Integral) {
+    assert(0 && "Passed template argument is not Integral");
+    return 0;
+  }
+
+  return TA.getAsIntegral().getZExtValue();
+}
+
 } // end: extern "C"
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/tools/libclang/libclang.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=219529&r1=219528&r2=219529&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.exports (original)
+++ cfe/trunk/tools/libclang/libclang.exports Fri Oct 10 15:01:05 2014
@@ -7,6 +7,11 @@ clang_CXXMethod_isPureVirtual
 clang_CXXMethod_isStatic
 clang_CXXMethod_isVirtual
 clang_Cursor_getArgument
+clang_Cursor_getNumTemplateArguments
+clang_Cursor_getTemplateArgumentKind
+clang_Cursor_getTemplateArgumentType
+clang_Cursor_getTemplateArgumentValue
+clang_Cursor_getTemplateArgumentUnsignedValue
 clang_Cursor_getBriefCommentText
 clang_Cursor_getCommentRange
 clang_Cursor_getMangling





More information about the cfe-commits mailing list