summaryrefslogtreecommitdiff
path: root/clang/bindings/python/tests/cindex
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au>2012-10-15 17:10:06 +1100
committerCarlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au>2012-10-15 17:10:06 +1100
commitbe1de4be954c80875ad4108e0a33e8e131b2f2c0 (patch)
tree1fbbecf276bf7c7bdcbb4dd446099d6d90eaa516 /clang/bindings/python/tests/cindex
parentc4626a62754862d20b41e8a46a3574264ea80e6d (diff)
parentf1bd2e48c5324d3f7cda4090c87f8a5b6f463ce2 (diff)
Merge branch 'master' of ssh://bitbucket.org/czan/honours
Diffstat (limited to 'clang/bindings/python/tests/cindex')
-rw-r--r--clang/bindings/python/tests/cindex/INPUTS/header1.h6
-rw-r--r--clang/bindings/python/tests/cindex/INPUTS/header2.h6
-rw-r--r--clang/bindings/python/tests/cindex/INPUTS/header3.h3
-rw-r--r--clang/bindings/python/tests/cindex/INPUTS/hello.cpp6
-rw-r--r--clang/bindings/python/tests/cindex/INPUTS/include.cpp5
-rw-r--r--clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c2
-rw-r--r--clang/bindings/python/tests/cindex/__init__.py0
-rw-r--r--clang/bindings/python/tests/cindex/test_cursor.py92
-rw-r--r--clang/bindings/python/tests/cindex/test_cursor_kind.py40
-rw-r--r--clang/bindings/python/tests/cindex/test_diagnostics.py82
-rw-r--r--clang/bindings/python/tests/cindex/test_file.py9
-rw-r--r--clang/bindings/python/tests/cindex/test_index.py15
-rw-r--r--clang/bindings/python/tests/cindex/test_location.py86
-rw-r--r--clang/bindings/python/tests/cindex/test_translation_unit.py84
-rw-r--r--clang/bindings/python/tests/cindex/test_type.py276
-rw-r--r--clang/bindings/python/tests/cindex/util.py65
16 files changed, 777 insertions, 0 deletions
diff --git a/clang/bindings/python/tests/cindex/INPUTS/header1.h b/clang/bindings/python/tests/cindex/INPUTS/header1.h
new file mode 100644
index 0000000..b4eacbe
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/INPUTS/header1.h
@@ -0,0 +1,6 @@
+#ifndef HEADER1
+#define HEADER1
+
+#include "header3.h"
+
+#endif
diff --git a/clang/bindings/python/tests/cindex/INPUTS/header2.h b/clang/bindings/python/tests/cindex/INPUTS/header2.h
new file mode 100644
index 0000000..c4eddc0
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/INPUTS/header2.h
@@ -0,0 +1,6 @@
+#ifndef HEADER2
+#define HEADER2
+
+#include "header3.h"
+
+#endif
diff --git a/clang/bindings/python/tests/cindex/INPUTS/header3.h b/clang/bindings/python/tests/cindex/INPUTS/header3.h
new file mode 100644
index 0000000..6dca764
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/INPUTS/header3.h
@@ -0,0 +1,3 @@
+// Not a guarded header!
+
+void f();
diff --git a/clang/bindings/python/tests/cindex/INPUTS/hello.cpp b/clang/bindings/python/tests/cindex/INPUTS/hello.cpp
new file mode 100644
index 0000000..7ef086e
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/INPUTS/hello.cpp
@@ -0,0 +1,6 @@
+#include "stdio.h"
+
+int main(int argc, char* argv[]) {
+ printf("hello world\n");
+ return 0;
+}
diff --git a/clang/bindings/python/tests/cindex/INPUTS/include.cpp b/clang/bindings/python/tests/cindex/INPUTS/include.cpp
new file mode 100644
index 0000000..60cfdaa
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/INPUTS/include.cpp
@@ -0,0 +1,5 @@
+#include "header1.h"
+#include "header2.h"
+#include "header1.h"
+
+int main() { }
diff --git a/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c b/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c
new file mode 100644
index 0000000..7196486
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c
@@ -0,0 +1,2 @@
+int DECL_ONE = 1;
+int DECL_TWO = 2;
diff --git a/clang/bindings/python/tests/cindex/__init__.py b/clang/bindings/python/tests/cindex/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/__init__.py
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py
new file mode 100644
index 0000000..9f02bb2
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -0,0 +1,92 @@
+from clang.cindex import CursorKind
+from clang.cindex import TypeKind
+from .util import get_cursor
+from .util import get_tu
+
+kInput = """\
+// FIXME: Find nicer way to drop builtins and other cruft.
+int start_decl;
+
+struct s0 {
+ int a;
+ int b;
+};
+
+struct s1;
+
+void f0(int a0, int a1) {
+ int l0, l1;
+
+ if (a0)
+ return;
+
+ for (;;) {
+ break;
+ }
+}
+"""
+
+def test_get_children():
+ tu = get_tu(kInput)
+
+ # Skip until past start_decl.
+ it = tu.cursor.get_children()
+ while it.next().spelling != 'start_decl':
+ pass
+
+ tu_nodes = list(it)
+
+ assert len(tu_nodes) == 3
+
+ assert tu_nodes[0] != tu_nodes[1]
+ assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
+ assert tu_nodes[0].spelling == 's0'
+ assert tu_nodes[0].is_definition() == True
+ assert tu_nodes[0].location.file.name == 't.c'
+ assert tu_nodes[0].location.line == 4
+ assert tu_nodes[0].location.column == 8
+ assert tu_nodes[0].hash > 0
+
+ s0_nodes = list(tu_nodes[0].get_children())
+ assert len(s0_nodes) == 2
+ assert s0_nodes[0].kind == CursorKind.FIELD_DECL
+ assert s0_nodes[0].spelling == 'a'
+ assert s0_nodes[0].type.kind == TypeKind.INT
+ assert s0_nodes[1].kind == CursorKind.FIELD_DECL
+ assert s0_nodes[1].spelling == 'b'
+ assert s0_nodes[1].type.kind == TypeKind.INT
+
+ assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
+ assert tu_nodes[1].spelling == 's1'
+ assert tu_nodes[1].displayname == 's1'
+ assert tu_nodes[1].is_definition() == False
+
+ assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
+ assert tu_nodes[2].spelling == 'f0'
+ assert tu_nodes[2].displayname == 'f0(int, int)'
+ assert tu_nodes[2].is_definition() == True
+
+def test_underlying_type():
+ tu = get_tu('typedef int foo;')
+ typedef = get_cursor(tu, 'foo')
+ assert typedef is not None
+
+ assert typedef.kind.is_declaration()
+ underlying = typedef.underlying_typedef_type
+ assert underlying.kind == TypeKind.INT
+
+def test_enum_type():
+ tu = get_tu('enum TEST { FOO=1, BAR=2 };')
+ enum = get_cursor(tu, 'TEST')
+ assert enum is not None
+
+ assert enum.kind == CursorKind.ENUM_DECL
+ enum_type = enum.enum_type
+ assert enum_type.kind == TypeKind.UINT
+
+def test_objc_type_encoding():
+ tu = get_tu('int i;', lang='objc')
+ i = get_cursor(tu, 'i')
+
+ assert i is not None
+ assert i.objc_type_encoding == 'i'
diff --git a/clang/bindings/python/tests/cindex/test_cursor_kind.py b/clang/bindings/python/tests/cindex/test_cursor_kind.py
new file mode 100644
index 0000000..f8466e5
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_cursor_kind.py
@@ -0,0 +1,40 @@
+from clang.cindex import CursorKind
+
+def test_name():
+ assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
+
+def test_get_all_kinds():
+ assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
+ assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
+
+def test_kind_groups():
+ """Check that every kind classifies to exactly one group."""
+
+ assert CursorKind.UNEXPOSED_DECL.is_declaration()
+ assert CursorKind.TYPE_REF.is_reference()
+ assert CursorKind.DECL_REF_EXPR.is_expression()
+ assert CursorKind.UNEXPOSED_STMT.is_statement()
+ assert CursorKind.INVALID_FILE.is_invalid()
+
+ assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
+ assert not CursorKind.TYPE_REF.is_translation_unit()
+
+ assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
+ assert not CursorKind.TYPE_REF.is_preprocessing()
+
+ assert CursorKind.UNEXPOSED_DECL.is_unexposed()
+ assert not CursorKind.TYPE_REF.is_unexposed()
+
+ for k in CursorKind.get_all_kinds():
+ group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
+ 'is_statement', 'is_invalid', 'is_attribute')
+ if getattr(k, n)()]
+
+ if k in ( CursorKind.TRANSLATION_UNIT,
+ CursorKind.MACRO_DEFINITION,
+ CursorKind.MACRO_INSTANTIATION,
+ CursorKind.INCLUSION_DIRECTIVE,
+ CursorKind.PREPROCESSING_DIRECTIVE):
+ assert len(group) == 0
+ else:
+ assert len(group) == 1
diff --git a/clang/bindings/python/tests/cindex/test_diagnostics.py b/clang/bindings/python/tests/cindex/test_diagnostics.py
new file mode 100644
index 0000000..48ab617
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_diagnostics.py
@@ -0,0 +1,82 @@
+from clang.cindex import *
+from .util import get_tu
+
+# FIXME: We need support for invalid translation units to test better.
+
+def test_diagnostic_warning():
+ tu = get_tu('int f0() {}\n')
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 1
+ assert tu.diagnostics[0].location.column == 11
+ assert (tu.diagnostics[0].spelling ==
+ 'control reaches end of non-void function')
+
+def test_diagnostic_note():
+ # FIXME: We aren't getting notes here for some reason.
+ tu = get_tu('#define A x\nvoid *A = 1;\n')
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 2
+ assert tu.diagnostics[0].location.column == 7
+ assert 'incompatible' in tu.diagnostics[0].spelling
+# assert tu.diagnostics[1].severity == Diagnostic.Note
+# assert tu.diagnostics[1].location.line == 1
+# assert tu.diagnostics[1].location.column == 11
+# assert tu.diagnostics[1].spelling == 'instantiated from'
+
+def test_diagnostic_fixit():
+ tu = get_tu('struct { int f0; } x = { f0 : 1 };')
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 1
+ assert tu.diagnostics[0].location.column == 26
+ assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
+ assert len(tu.diagnostics[0].fixits) == 1
+ assert tu.diagnostics[0].fixits[0].range.start.line == 1
+ assert tu.diagnostics[0].fixits[0].range.start.column == 26
+ assert tu.diagnostics[0].fixits[0].range.end.line == 1
+ assert tu.diagnostics[0].fixits[0].range.end.column == 30
+ assert tu.diagnostics[0].fixits[0].value == '.f0 = '
+
+def test_diagnostic_range():
+ tu = get_tu('void f() { int i = "a" + 1; }')
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 1
+ assert tu.diagnostics[0].location.column == 16
+ assert tu.diagnostics[0].spelling.startswith('incompatible pointer to')
+ assert len(tu.diagnostics[0].fixits) == 0
+ assert len(tu.diagnostics[0].ranges) == 1
+ assert tu.diagnostics[0].ranges[0].start.line == 1
+ assert tu.diagnostics[0].ranges[0].start.column == 20
+ assert tu.diagnostics[0].ranges[0].end.line == 1
+ assert tu.diagnostics[0].ranges[0].end.column == 27
+ try:
+ tu.diagnostics[0].ranges[1].start.line
+ except IndexError:
+ assert True
+ else:
+ assert False
+
+def test_diagnostic_category():
+ """Ensure that category properties work."""
+ tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert d.severity == Diagnostic.Warning
+ assert d.location.line == 1
+ assert d.location.column == 11
+
+ assert d.category_number == 2
+ assert d.category_name == 'Semantic Issue'
+
+def test_diagnostic_option():
+ """Ensure that category option properties work."""
+ tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert d.option == '-Wunused-parameter'
+ assert d.disable_option == '-Wno-unused-parameter'
diff --git a/clang/bindings/python/tests/cindex/test_file.py b/clang/bindings/python/tests/cindex/test_file.py
new file mode 100644
index 0000000..146e8c5
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_file.py
@@ -0,0 +1,9 @@
+from clang.cindex import Index, File
+
+def test_file():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c', "")])
+ file = File.from_name(tu, "t.c")
+ assert str(file) == "t.c"
+ assert file.name == "t.c"
+ assert repr(file) == "<File: t.c>"
diff --git a/clang/bindings/python/tests/cindex/test_index.py b/clang/bindings/python/tests/cindex/test_index.py
new file mode 100644
index 0000000..dc173f0
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_index.py
@@ -0,0 +1,15 @@
+from clang.cindex import *
+import os
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_create():
+ index = Index.create()
+
+# FIXME: test Index.read
+
+def test_parse():
+ index = Index.create()
+ assert isinstance(index, Index)
+ tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
+ assert isinstance(tu, TranslationUnit)
diff --git a/clang/bindings/python/tests/cindex/test_location.py b/clang/bindings/python/tests/cindex/test_location.py
new file mode 100644
index 0000000..528676e
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_location.py
@@ -0,0 +1,86 @@
+from clang.cindex import Cursor
+from clang.cindex import File
+from clang.cindex import SourceLocation
+from clang.cindex import SourceRange
+from .util import get_cursor
+from .util import get_tu
+
+baseInput="int one;\nint two;\n"
+
+def assert_location(loc, line, column, offset):
+ assert loc.line == line
+ assert loc.column == column
+ assert loc.offset == offset
+
+def test_location():
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert one is not None
+ assert two is not None
+
+ assert_location(one.location,line=1,column=5,offset=4)
+ assert_location(two.location,line=2,column=5,offset=13)
+
+ # adding a linebreak at top should keep columns same
+ tu = get_tu('\n' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert one is not None
+ assert two is not None
+
+ assert_location(one.location,line=2,column=5,offset=5)
+ assert_location(two.location,line=3,column=5,offset=14)
+
+ # adding a space should affect column on first line only
+ tu = get_tu(' ' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert_location(one.location,line=1,column=6,offset=5)
+ assert_location(two.location,line=2,column=5,offset=14)
+
+ # define the expected location ourselves and see if it matches
+ # the returned location
+ tu = get_tu(baseInput)
+
+ file = File.from_name(tu, 't.c')
+ location = SourceLocation.from_position(tu, file, 1, 5)
+ cursor = Cursor.from_location(tu, location)
+
+ one = get_cursor(tu, 'one')
+ assert one is not None
+ assert one == cursor
+
+ # Ensure locations referring to the same entity are equivalent.
+ location2 = SourceLocation.from_position(tu, file, 1, 5)
+ assert location == location2
+ location3 = SourceLocation.from_position(tu, file, 1, 4)
+ assert location2 != location3
+
+def test_extent():
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert_location(one.extent.start,line=1,column=1,offset=0)
+ assert_location(one.extent.end,line=1,column=8,offset=7)
+ assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
+
+ assert_location(two.extent.start,line=2,column=1,offset=9)
+ assert_location(two.extent.end,line=2,column=8,offset=16)
+ assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two"
+
+ file = File.from_name(tu, 't.c')
+ location1 = SourceLocation.from_position(tu, file, 1, 1)
+ location2 = SourceLocation.from_position(tu, file, 1, 8)
+
+ range1 = SourceRange.from_locations(location1, location2)
+ range2 = SourceRange.from_locations(location1, location2)
+ assert range1 == range2
+
+ location3 = SourceLocation.from_position(tu, file, 1, 6)
+ range3 = SourceRange.from_locations(location1, location3)
+ assert range1 != range3
diff --git a/clang/bindings/python/tests/cindex/test_translation_unit.py b/clang/bindings/python/tests/cindex/test_translation_unit.py
new file mode 100644
index 0000000..2e65d95
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_translation_unit.py
@@ -0,0 +1,84 @@
+from clang.cindex import *
+import os
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_spelling():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ index = Index.create()
+ tu = index.parse(path)
+ assert tu.spelling == path
+
+def test_cursor():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ index = Index.create()
+ tu = index.parse(path)
+ c = tu.cursor
+ assert isinstance(c, Cursor)
+ assert c.kind is CursorKind.TRANSLATION_UNIT
+
+def test_parse_arguments():
+ path = os.path.join(kInputsDir, 'parse_arguments.c')
+ index = Index.create()
+ tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'hello'
+ assert spellings[-1] == 'hi'
+
+def test_reparse_arguments():
+ path = os.path.join(kInputsDir, 'parse_arguments.c')
+ index = Index.create()
+ tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
+ tu.reparse()
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'hello'
+ assert spellings[-1] == 'hi'
+
+def test_unsaved_files():
+ index = Index.create()
+ tu = index.parse('fake.c', ['-I./'], unsaved_files = [
+ ('fake.c', """
+#include "fake.h"
+int x;
+int SOME_DEFINE;
+"""),
+ ('./fake.h', """
+#define SOME_DEFINE y
+""")
+ ])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'x'
+ assert spellings[-1] == 'y'
+
+def test_unsaved_files_2():
+ import StringIO
+ index = Index.create()
+ tu = index.parse('fake.c', unsaved_files = [
+ ('fake.c', StringIO.StringIO('int x;'))])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-1] == 'x'
+
+def normpaths_equal(path1, path2):
+ """ Compares two paths for equality after normalizing them with
+ os.path.normpath
+ """
+ return os.path.normpath(path1) == os.path.normpath(path2)
+
+def test_includes():
+ def eq(expected, actual):
+ if not actual.is_input_file:
+ return normpaths_equal(expected[0], actual.source.name) and \
+ normpaths_equal(expected[1], actual.include.name)
+ else:
+ return normpaths_equal(expected[1], actual.include.name)
+
+ src = os.path.join(kInputsDir, 'include.cpp')
+ h1 = os.path.join(kInputsDir, "header1.h")
+ h2 = os.path.join(kInputsDir, "header2.h")
+ h3 = os.path.join(kInputsDir, "header3.h")
+ inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
+
+ index = Index.create()
+ tu = index.parse(src)
+ for i in zip(inc, tu.get_includes()):
+ assert eq(i[0], i[1])
diff --git a/clang/bindings/python/tests/cindex/test_type.py b/clang/bindings/python/tests/cindex/test_type.py
new file mode 100644
index 0000000..03621f3
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_type.py
@@ -0,0 +1,276 @@
+from clang.cindex import CursorKind
+from clang.cindex import TypeKind
+from nose.tools import raises
+from .util import get_cursor
+from .util import get_tu
+
+kInput = """\
+
+typedef int I;
+
+struct teststruct {
+ int a;
+ I b;
+ long c;
+ unsigned long d;
+ signed long e;
+ const int f;
+ int *g;
+ int ***h;
+};
+
+"""
+
+def test_a_struct():
+ tu = get_tu(kInput)
+
+ teststruct = get_cursor(tu, 'teststruct')
+ assert teststruct is not None, "Could not find teststruct."
+ fields = list(teststruct.get_children())
+ assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
+
+ assert fields[0].spelling == 'a'
+ assert not fields[0].type.is_const_qualified()
+ assert fields[0].type.kind == TypeKind.INT
+ assert fields[0].type.get_canonical().kind == TypeKind.INT
+
+ assert fields[1].spelling == 'b'
+ assert not fields[1].type.is_const_qualified()
+ assert fields[1].type.kind == TypeKind.TYPEDEF
+ assert fields[1].type.get_canonical().kind == TypeKind.INT
+ assert fields[1].type.get_declaration().spelling == 'I'
+
+ assert fields[2].spelling == 'c'
+ assert not fields[2].type.is_const_qualified()
+ assert fields[2].type.kind == TypeKind.LONG
+ assert fields[2].type.get_canonical().kind == TypeKind.LONG
+
+ assert fields[3].spelling == 'd'
+ assert not fields[3].type.is_const_qualified()
+ assert fields[3].type.kind == TypeKind.ULONG
+ assert fields[3].type.get_canonical().kind == TypeKind.ULONG
+
+ assert fields[4].spelling == 'e'
+ assert not fields[4].type.is_const_qualified()
+ assert fields[4].type.kind == TypeKind.LONG
+ assert fields[4].type.get_canonical().kind == TypeKind.LONG
+
+ assert fields[5].spelling == 'f'
+ assert fields[5].type.is_const_qualified()
+ assert fields[5].type.kind == TypeKind.INT
+ assert fields[5].type.get_canonical().kind == TypeKind.INT
+
+ assert fields[6].spelling == 'g'
+ assert not fields[6].type.is_const_qualified()
+ assert fields[6].type.kind == TypeKind.POINTER
+ assert fields[6].type.get_pointee().kind == TypeKind.INT
+
+ assert fields[7].spelling == 'h'
+ assert not fields[7].type.is_const_qualified()
+ assert fields[7].type.kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
+
+constarrayInput="""
+struct teststruct {
+ void *A[2];
+};
+"""
+def testConstantArray():
+ tu = get_tu(constarrayInput)
+
+ teststruct = get_cursor(tu, 'teststruct')
+ assert teststruct is not None, "Didn't find teststruct??"
+ fields = list(teststruct.get_children())
+ assert fields[0].spelling == 'A'
+ assert fields[0].type.kind == TypeKind.CONSTANTARRAY
+ assert fields[0].type.get_array_element_type() is not None
+ assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
+ assert fields[0].type.get_array_size() == 2
+
+def test_equal():
+ """Ensure equivalence operators work on Type."""
+ source = 'int a; int b; void *v;'
+ tu = get_tu(source)
+
+ a = get_cursor(tu, 'a')
+ b = get_cursor(tu, 'b')
+ v = get_cursor(tu, 'v')
+
+ assert a is not None
+ assert b is not None
+ assert v is not None
+
+ assert a.type == b.type
+ assert a.type != v.type
+
+ assert a.type != None
+ assert a.type != 'foo'
+
+def test_typekind_spelling():
+ """Ensure TypeKind.spelling works."""
+ tu = get_tu('int a;')
+ a = get_cursor(tu, 'a')
+
+ assert a is not None
+ assert a.type.kind.spelling == 'Int'
+
+def test_function_argument_types():
+ """Ensure that Type.argument_types() works as expected."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ assert f is not None
+
+ args = f.type.argument_types()
+ assert args is not None
+ assert len(args) == 2
+
+ t0 = args[0]
+ assert t0 is not None
+ assert t0.kind == TypeKind.INT
+
+ t1 = args[1]
+ assert t1 is not None
+ assert t1.kind == TypeKind.INT
+
+ args2 = list(args)
+ assert len(args2) == 2
+ assert t0 == args2[0]
+ assert t1 == args2[1]
+
+@raises(TypeError)
+def test_argument_types_string_key():
+ """Ensure that non-int keys raise a TypeError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ assert f is not None
+
+ args = f.type.argument_types()
+ assert len(args) == 2
+
+ args['foo']
+
+@raises(IndexError)
+def test_argument_types_negative_index():
+ """Ensure that negative indexes on argument_types Raises an IndexError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.argument_types()
+
+ args[-1]
+
+@raises(IndexError)
+def test_argument_types_overflow_index():
+ """Ensure that indexes beyond the length of Type.argument_types() raise."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.argument_types()
+
+ args[2]
+
+@raises(Exception)
+def test_argument_types_invalid_type():
+ """Ensure that obtaining argument_types on a Type without them raises."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+
+ i.type.argument_types()
+
+def test_is_pod():
+ """Ensure Type.is_pod() works."""
+ tu = get_tu('int i; void f();')
+ i = get_cursor(tu, 'i')
+ f = get_cursor(tu, 'f')
+
+ assert i is not None
+ assert f is not None
+
+ assert i.type.is_pod()
+ assert not f.type.is_pod()
+
+def test_function_variadic():
+ """Ensure Type.is_function_variadic works."""
+
+ source ="""
+#include <stdarg.h>
+
+void foo(int a, ...);
+void bar(int a, int b);
+"""
+
+ tu = get_tu(source)
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+
+ assert foo is not None
+ assert bar is not None
+
+ assert isinstance(foo.type.is_function_variadic(), bool)
+ assert foo.type.is_function_variadic()
+ assert not bar.type.is_function_variadic()
+
+def test_element_type():
+ """Ensure Type.element_type works."""
+ tu = get_tu('int i[5];')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+
+ assert i.type.kind == TypeKind.CONSTANTARRAY
+ assert i.type.element_type.kind == TypeKind.INT
+
+@raises(Exception)
+def test_invalid_element_type():
+ """Ensure Type.element_type raises if type doesn't have elements."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+ i.element_type
+
+def test_element_count():
+ """Ensure Type.element_count works."""
+ tu = get_tu('int i[5]; int j;')
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert i.type.element_count == 5
+
+ try:
+ j.type.element_count
+ assert False
+ except:
+ assert True
+
+def test_is_volatile_qualified():
+ """Ensure Type.is_volatile_qualified works."""
+
+ tu = get_tu('volatile int i = 4; int j = 2;')
+
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert isinstance(i.type.is_volatile_qualified(), bool)
+ assert i.type.is_volatile_qualified()
+ assert not j.type.is_volatile_qualified()
+
+def test_is_restrict_qualified():
+ """Ensure Type.is_restrict_qualified works."""
+
+ tu = get_tu('struct s { void * restrict i; void * j };')
+
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert isinstance(i.type.is_restrict_qualified(), bool)
+ assert i.type.is_restrict_qualified()
+ assert not j.type.is_restrict_qualified()
diff --git a/clang/bindings/python/tests/cindex/util.py b/clang/bindings/python/tests/cindex/util.py
new file mode 100644
index 0000000..388b269
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/util.py
@@ -0,0 +1,65 @@
+# This file provides common utility functions for the test suite.
+
+from clang.cindex import Cursor
+from clang.cindex import Index
+
+def get_tu(source, lang='c', all_warnings=False):
+ """Obtain a translation unit from source and language.
+
+ By default, the translation unit is created from source file "t.<ext>"
+ where <ext> is the default file extension for the specified language. By
+ default it is C, so "t.c" is the default file name.
+
+ Supported languages are {c, cpp, objc}.
+
+ all_warnings is a convenience argument to enable all compiler warnings.
+ """
+ name = 't.c'
+ if lang == 'cpp':
+ name = 't.cpp'
+ elif lang == 'objc':
+ name = 't.m'
+ elif lang != 'c':
+ raise Exception('Unknown language: %s' % lang)
+
+ args = []
+ if all_warnings:
+ args = ['-Wall', '-Wextra']
+
+ index = Index.create()
+ tu = index.parse(name, args=args, unsaved_files=[(name, source)])
+ assert tu is not None
+ return tu
+
+def get_cursor(source, spelling):
+ """Obtain a cursor from a source object.
+
+ This provides a convenient search mechanism to find a cursor with specific
+ spelling within a source. The first argument can be either a
+ TranslationUnit or Cursor instance.
+
+ If the cursor is not found, None is returned.
+ """
+ children = []
+ if isinstance(source, Cursor):
+ children = source.get_children()
+ else:
+ # Assume TU
+ children = source.cursor.get_children()
+
+ for cursor in children:
+ if cursor.spelling == spelling:
+ return cursor
+
+ # Recurse into children.
+ result = get_cursor(cursor, spelling)
+ if result is not None:
+ return result
+
+ return None
+
+
+__all__ = [
+ 'get_cursor',
+ 'get_tu',
+]