summaryrefslogtreecommitdiffstats
path: root/bindings
diff options
context:
space:
mode:
authorEli Bendersky <eliben@google.com>2014-10-10 20:01:05 +0000
committerEli Bendersky <eliben@google.com>2014-10-10 20:01:05 +0000
commita0b1e640c5872ea7bd3f297b772f6842aabe5d4d (patch)
tree0ddf747eb590189d2d8bfe929d8d089c5c590410 /bindings
parent2fdc497405b20e3d4a02e8b8a121f63e4baa3587 (diff)
Add libclang capabilities to retriete template arguments from specializations.
Includes Python bindings. Reviewed in http://reviews.llvm.org/D5621 Patch by Rob Springer git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219529 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'bindings')
-rw-r--r--bindings/python/clang/cindex.py204
-rw-r--r--bindings/python/tests/cindex/test_cursor.py44
2 files changed, 142 insertions, 106 deletions
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 68f7e48fc6..8bcf9c3bda 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -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 = CursorKind(503)
# 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),
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index d4ee9daa96..a5224aafab 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -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')