I incorporated feedback from Tobias and exposed arguments as an
iterable and indexable container object.
---
bindings/python/clang/cindex.py | 47 +++++++++++++++++++
bindings/python/tests/cindex/test_type.py | 69 +++++++++++++++++++++++++++++
2 files changed, 116 insertions(+), 0 deletions(-)
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 8c69790..991a6b1 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -1132,16 +1132,54 @@ class Type(Structure):
"""
_fields_ = [("_kind_id", c_int), ("data", c_void_p * 2)]
@property
def kind(self):
"""Return the kind of this type."""
return TypeKind.from_id(self._kind_id)
+ def arguments(self):
+ """Retrieve a container for the non-variadic arguments for this type.
+
+ The returned object is iterable and indexable. Each item in the
+ container is a Type instance.
+ """
+ class ArgumentsIterator(object):
+ def __init__(self, parent):
+ self.parent = parent
+ self.length = None
+
+ def __len__(self):
+ if self.length is None:
+ self.length = Type_get_num_arg_types(self.parent)
+
+ return self.length
+
+ def __getitem__(self, key):
+ # FIXME Support slice objects.
+ if not isinstance(key, int):
+ raise TypeError("Must supply a non-negative int.")
+
+ if key < 0:
+ raise IndexError("Only non-negative indexes are accepted.")
+
+ result = Type_get_arg_type(self.parent, key)
+ if result.kind == TypeKind.INVALID:
+ raise IndexError("Argument could not be retrieved.")
+
+ return result
+
+ def __iter__(self):
+ for i in range(0, len(self)):
+ yield self[i]
+
+ assert self.kind == TypeKind.FUNCTIONPROTO
+ return ArgumentsIterator(self)
+
@property
def element_type(self):
"""Retrieve the Type of elements within this Type.
If accessed on a type that is not an array, complex, or vector type, an
exception will be raised.
"""
result = Type_get_element_type(self)
@@ -1919,17 +1957,26 @@ Type_get_declaration.argtypes = [Type]
Type_get_declaration.restype = Cursor
Type_get_declaration.errcheck = Cursor.from_result
Type_get_result = lib.clang_getResultType
Type_get_result.argtypes = [Type]
Type_get_result.restype = Type
Type_get_result.errcheck = Type.from_result
+Type_get_num_arg_types = lib.clang_getNumArgTypes
+Type_get_num_arg_types.argtypes = [Type]
+Type_get_num_arg_types.restype = c_uint
+
+Type_get_arg_type = lib.clang_getArgType
+Type_get_arg_type.argtypes = [Type, c_uint]
+Type_get_arg_type.restype = Type
+Type_get_arg_type.errcheck = Type.from_result
Type_get_element_type = lib.clang_getElementType
+
Type_get_element_type.argtypes = [Type]
Type_get_element_type.restype = Type
Type_get_element_type.errcheck = Type.from_result
Type_get_num_elements = lib.clang_getNumElements
Type_get_num_elements.argtypes = [Type]
Type_get_num_elements.restype = c_longlong
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
index 449cf9c..925f93b 100644
--- a/bindings/python/tests/cindex/test_type.py
+++ b/bindings/python/tests/cindex/test_type.py
@@ -24,16 +24,23 @@ struct teststruct {
def get_tu(source=kInput, lang='cpp'):
name = 't.cpp'
if lang == 'c':
name = 't.c'
index = Index.create()
return index.parse(name, unsaved_files=[(name, source)])
+def get_cursor(tu, spelling):
+ for cursor in tu.cursor.get_children():
+ if cursor.spelling == spelling:
+ return cursor
+
+ return None
+
def test_a_struct():
index = Index.create()
tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
for n in tu.cursor.get_children():
if n.spelling == 'teststruct':
fields = list(n.get_children())
@@ -122,16 +129,78 @@ def test_equal():
elif cursor.spelling == 'b':
b = cursor
assert a is not None
assert b is not None
assert a.type == b.type
+def test_function_arguments():
+ """Ensure that Type.arguments() works as expected."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ ok_(f is not None)
+
+ args = f.type.arguments()
+ ok_(args is not None)
+ ok_(len(args) == 2)
+
+ t0 = args[0]
+ ok_(t0 is not None)
+ ok_(t0.kind == TypeKind.INT)
+
+ t1 = args[1]
+ ok_(t1 is not None)
+ ok_(t1.kind == TypeKind.INT)
+
+ args2 = list(args)
+ ok_(len(args2) == 2)
+ ok_(t0 == args2[0])
+ ok_(t1 == args2[1])
+
+@raises(TypeError)
+def test_arguments_string_key():
+ """Ensure that non-int keys raise a TypeError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ ok_(f is not None)
+
+ args = f.type.arguments()
+ ok_(len(args) == 2)
+
+ args['foo']
+
+@raises(IndexError)
+def test_arguments_negative_index():
+ """Ensure that negative indexes on arguments Raises an IndexError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.arguments()
+
+ args[-1]
+
+@raises(IndexError)
+def test_arguments_overflow_index():
+ """Ensure that indexes beyond the length of Type.arguments() raise."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.arguments()
+
+ args[2]
+
+@raises(Exception)
+def test_arguments_invalid_type():
+ """Ensure that obtaining arguments on a type without them raises."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ ok_(i is not None)
+
+ i.type.arguments()
+
def test_is_pod():
index = Index.create()
tu = index.parse('t.c', unsaved_files=[('t.c', 'int i; void f();')])
assert tu is not None
i, f = None, None
for cursor in tu.cursor.get_children():
if cursor.spelling == 'i':
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits