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

Reply via email to